xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/target-memory.c (revision ccd9df534e375a4366c5b55f23782053c7a98d82)
1 /* Parts of target interface that deal with accessing memory and memory-like
2    objects.
3 
4    Copyright (C) 2006-2020 Free Software Foundation, Inc.
5 
6    This file is part of GDB.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20 
21 #include "defs.h"
22 #include "target.h"
23 #include "memory-map.h"
24 
25 #include "gdbsupport/gdb_sys_time.h"
26 #include <algorithm>
27 
28 static bool
29 compare_block_starting_address (const memory_write_request &a_req,
30 				const memory_write_request &b_req)
31 {
32   return a_req.begin < b_req.begin;
33 }
34 
35 /* Adds to RESULT all memory write requests from BLOCK that are
36    in [BEGIN, END) range.
37 
38    If any memory request is only partially in the specified range,
39    that part of the memory request will be added.  */
40 
41 static void
42 claim_memory (const std::vector<memory_write_request> &blocks,
43 	      std::vector<memory_write_request> *result,
44 	      ULONGEST begin,
45 	      ULONGEST end)
46 {
47   ULONGEST claimed_begin;
48   ULONGEST claimed_end;
49 
50   for (const memory_write_request &r : blocks)
51     {
52       /* If the request doesn't overlap [BEGIN, END), skip it.  We
53 	 must handle END == 0 meaning the top of memory; we don't yet
54 	 check for R->end == 0, which would also mean the top of
55 	 memory, but there's an assertion in
56 	 target_write_memory_blocks which checks for that.  */
57 
58       if (begin >= r.end)
59 	continue;
60       if (end != 0 && end <= r.begin)
61 	continue;
62 
63       claimed_begin = std::max (begin, r.begin);
64       if (end == 0)
65 	claimed_end = r.end;
66       else
67 	claimed_end = std::min (end, r.end);
68 
69       if (claimed_begin == r.begin && claimed_end == r.end)
70 	result->push_back (r);
71       else
72 	{
73 	  struct memory_write_request n = r;
74 
75 	  n.begin = claimed_begin;
76 	  n.end = claimed_end;
77 	  n.data += claimed_begin - r.begin;
78 
79 	  result->push_back (n);
80 	}
81     }
82 }
83 
84 /* Given a vector of struct memory_write_request objects in BLOCKS,
85    add memory requests for flash memory into FLASH_BLOCKS, and for
86    regular memory to REGULAR_BLOCKS.  */
87 
88 static void
89 split_regular_and_flash_blocks (const std::vector<memory_write_request> &blocks,
90 				std::vector<memory_write_request> *regular_blocks,
91 				std::vector<memory_write_request> *flash_blocks)
92 {
93   struct mem_region *region;
94   CORE_ADDR cur_address;
95 
96   /* This implementation runs in O(length(regions)*length(blocks)) time.
97      However, in most cases the number of blocks will be small, so this does
98      not matter.
99 
100      Note also that it's extremely unlikely that a memory write request
101      will span more than one memory region, however for safety we handle
102      such situations.  */
103 
104   cur_address = 0;
105   while (1)
106     {
107       std::vector<memory_write_request> *r;
108 
109       region = lookup_mem_region (cur_address);
110       r = region->attrib.mode == MEM_FLASH ? flash_blocks : regular_blocks;
111       cur_address = region->hi;
112       claim_memory (blocks, r, region->lo, region->hi);
113 
114       if (cur_address == 0)
115 	break;
116     }
117 }
118 
119 /* Given an ADDRESS, if BEGIN is non-NULL this function sets *BEGIN
120    to the start of the flash block containing the address.  Similarly,
121    if END is non-NULL *END will be set to the address one past the end
122    of the block containing the address.  */
123 
124 static void
125 block_boundaries (CORE_ADDR address, CORE_ADDR *begin, CORE_ADDR *end)
126 {
127   struct mem_region *region;
128   unsigned blocksize;
129   CORE_ADDR offset_in_region;
130 
131   region = lookup_mem_region (address);
132   gdb_assert (region->attrib.mode == MEM_FLASH);
133   blocksize = region->attrib.blocksize;
134 
135   offset_in_region = address - region->lo;
136 
137   if (begin)
138     *begin = region->lo + offset_in_region / blocksize * blocksize;
139   if (end)
140     *end = region->lo + (offset_in_region + blocksize - 1) / blocksize * blocksize;
141 }
142 
143 /* Given the list of memory requests to be WRITTEN, this function
144    returns write requests covering each group of flash blocks which must
145    be erased.  */
146 
147 static std::vector<memory_write_request>
148 blocks_to_erase (const std::vector<memory_write_request> &written)
149 {
150   std::vector<memory_write_request> result;
151 
152   for (const memory_write_request &request : written)
153     {
154       CORE_ADDR begin, end;
155 
156       block_boundaries (request.begin, &begin, 0);
157       block_boundaries (request.end - 1, 0, &end);
158 
159       if (!result.empty () && result.back ().end >= begin)
160 	result.back ().end = end;
161       else
162 	result.emplace_back (begin, end);
163     }
164 
165   return result;
166 }
167 
168 /* Given ERASED_BLOCKS, a list of blocks that will be erased with
169    flash erase commands, and WRITTEN_BLOCKS, the list of memory
170    addresses that will be written, compute the set of memory addresses
171    that will be erased but not rewritten (e.g. padding within a block
172    which is only partially filled by "load").  */
173 
174 static std::vector<memory_write_request>
175 compute_garbled_blocks (const std::vector<memory_write_request> &erased_blocks,
176 			const std::vector<memory_write_request> &written_blocks)
177 {
178   std::vector<memory_write_request> result;
179 
180   unsigned j;
181   unsigned je = written_blocks.size ();
182 
183   /* Look at each erased memory_write_request in turn, and
184      see what part of it is subsequently written to.
185 
186      This implementation is O(length(erased) * length(written)).  If
187      the lists are sorted at this point it could be rewritten more
188      efficiently, but the complexity is not generally worthwhile.  */
189 
190   for (const memory_write_request &erased_iter : erased_blocks)
191     {
192       /* Make a deep copy -- it will be modified inside the loop, but
193 	 we don't want to modify original vector.  */
194       struct memory_write_request erased = erased_iter;
195 
196       for (j = 0; j != je;)
197 	{
198 	  const memory_write_request *written = &written_blocks[j];
199 
200 	  /* Now try various cases.  */
201 
202 	  /* If WRITTEN is fully to the left of ERASED, check the next
203 	     written memory_write_request.  */
204 	  if (written->end <= erased.begin)
205 	    {
206 	      ++j;
207 	      continue;
208 	    }
209 
210 	  /* If WRITTEN is fully to the right of ERASED, then ERASED
211 	     is not written at all.  WRITTEN might affect other
212 	     blocks.  */
213 	  if (written->begin >= erased.end)
214 	    {
215 	      result.push_back (erased);
216 	      goto next_erased;
217 	    }
218 
219 	  /* If all of ERASED is completely written, we can move on to
220 	     the next erased region.  */
221 	  if (written->begin <= erased.begin
222 	      && written->end >= erased.end)
223 	    {
224 	      goto next_erased;
225 	    }
226 
227 	  /* If there is an unwritten part at the beginning of ERASED,
228 	     then we should record that part and try this inner loop
229 	     again for the remainder.  */
230 	  if (written->begin > erased.begin)
231 	    {
232 	      result.emplace_back (erased.begin, written->begin);
233 	      erased.begin = written->begin;
234 	      continue;
235 	    }
236 
237 	  /* If there is an unwritten part at the end of ERASED, we
238 	     forget about the part that was written to and wait to see
239 	     if the next write request writes more of ERASED.  We can't
240 	     push it yet.  */
241 	  if (written->end < erased.end)
242 	    {
243 	      erased.begin = written->end;
244 	      ++j;
245 	      continue;
246 	    }
247 	}
248 
249       /* If we ran out of write requests without doing anything about
250 	 ERASED, then that means it's really erased.  */
251       result.push_back (erased);
252 
253     next_erased:
254       ;
255     }
256 
257   return result;
258 }
259 
260 int
261 target_write_memory_blocks (const std::vector<memory_write_request> &requests,
262 			    enum flash_preserve_mode preserve_flash_p,
263 			    void (*progress_cb) (ULONGEST, void *))
264 {
265   std::vector<memory_write_request> blocks = requests;
266   std::vector<memory_write_request> regular;
267   std::vector<memory_write_request> flash;
268   std::vector<memory_write_request> erased, garbled;
269 
270   /* END == 0 would represent wraparound: a write to the very last
271      byte of the address space.  This file was not written with that
272      possibility in mind.  This is fixable, but a lot of work for a
273      rare problem; so for now, fail noisily here instead of obscurely
274      later.  */
275   for (const memory_write_request &iter : requests)
276     gdb_assert (iter.end != 0);
277 
278   /* Sort the blocks by their start address.  */
279   std::sort (blocks.begin (), blocks.end (), compare_block_starting_address);
280 
281   /* Split blocks into list of regular memory blocks,
282      and list of flash memory blocks.  */
283   split_regular_and_flash_blocks (blocks, &regular, &flash);
284 
285   /* If a variable is added to forbid flash write, even during "load",
286      it should be checked here.  Similarly, if this function is used
287      for other situations besides "load" in which writing to flash
288      is undesirable, that should be checked here.  */
289 
290   /* Find flash blocks to erase.  */
291   erased = blocks_to_erase (flash);
292 
293   /* Find what flash regions will be erased, and not overwritten; then
294      either preserve or discard the old contents.  */
295   garbled = compute_garbled_blocks (erased, flash);
296 
297   std::vector<gdb::unique_xmalloc_ptr<gdb_byte>> mem_holders;
298   if (!garbled.empty ())
299     {
300       if (preserve_flash_p == flash_preserve)
301 	{
302 	  /* Read in regions that must be preserved and add them to
303 	     the list of blocks we read.  */
304 	  for (memory_write_request &iter : garbled)
305 	    {
306 	      gdb_assert (iter.data == NULL);
307 	      gdb::unique_xmalloc_ptr<gdb_byte> holder
308 		((gdb_byte *) xmalloc (iter.end - iter.begin));
309 	      iter.data = holder.get ();
310 	      mem_holders.push_back (std::move (holder));
311 	      int err = target_read_memory (iter.begin, iter.data,
312 					    iter.end - iter.begin);
313 	      if (err != 0)
314 		return err;
315 
316 	      flash.push_back (iter);
317 	    }
318 
319 	  std::sort (flash.begin (), flash.end (),
320 		     compare_block_starting_address);
321 	}
322     }
323 
324   /* We could coalesce adjacent memory blocks here, to reduce the
325      number of write requests for small sections.  However, we would
326      have to reallocate and copy the data pointers, which could be
327      large; large sections are more common in loadable objects than
328      large numbers of small sections (although the reverse can be true
329      in object files).  So, we issue at least one write request per
330      passed struct memory_write_request.  The remote stub will still
331      have the opportunity to batch flash requests.  */
332 
333   /* Write regular blocks.  */
334   for (const memory_write_request &iter : regular)
335     {
336       LONGEST len;
337 
338       len = target_write_with_progress (current_top_target (),
339 					TARGET_OBJECT_MEMORY, NULL,
340 					iter.data, iter.begin,
341 					iter.end - iter.begin,
342 					progress_cb, iter.baton);
343       if (len < (LONGEST) (iter.end - iter.begin))
344 	{
345 	  /* Call error?  */
346 	  return -1;
347 	}
348     }
349 
350   if (!erased.empty ())
351     {
352       /* Erase all pages.  */
353       for (const memory_write_request &iter : erased)
354 	target_flash_erase (iter.begin, iter.end - iter.begin);
355 
356       /* Write flash data.  */
357       for (const memory_write_request &iter : flash)
358 	{
359 	  LONGEST len;
360 
361 	  len = target_write_with_progress (current_top_target (),
362 					    TARGET_OBJECT_FLASH, NULL,
363 					    iter.data, iter.begin,
364 					    iter.end - iter.begin,
365 					    progress_cb, iter.baton);
366 	  if (len < (LONGEST) (iter.end - iter.begin))
367 	    error (_("Error writing data to flash"));
368 	}
369 
370       target_flash_done ();
371     }
372 
373   return 0;
374 }
375