]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/tools/configtool/standalone/wxwin/memmap.cpp
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / memmap.cpp
1 //####COPYRIGHTBEGIN####
2 //                                                                          
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 //
6 // This program is part of the eCos host tools.
7 //
8 // This program is free software; you can redistribute it and/or modify it 
9 // under the terms of the GNU General Public License as published by the Free 
10 // Software Foundation; either version 2 of the License, or (at your option) 
11 // any later version.
12 // 
13 // This program is distributed in the hope that it will be useful, but WITHOUT 
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
15 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
16 // more details.
17 // 
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc., 
20 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 //
22 // ----------------------------------------------------------------------------
23 //                                                                          
24 //####COPYRIGHTEND####
25 //=================================================================
26 //
27 //        memmap.cpp
28 //
29 //        Memory Layout Tool map data structure manipulation class
30 //
31 //=================================================================
32 //#####DESCRIPTIONBEGIN####
33 //
34 // Author(s):     John Dallaway
35 // Contact(s):    jld
36 // Date:          1998/07/29 $RcsDate$ {or whatever}
37 // Version:       0.00+  $RcsVersion$ {or whatever}
38 // Purpose:       Provides functions to create and destroy memory regions
39 //                and sections within the memory map.
40 // Description:   Each function manipulates data structures representing
41 //                memory regions, memory sections and the view of memory
42 //                sections as presented to the user. The section view
43 //                structure organises the sections by region and 
44 //                will contain two instances of each relocated section 
45 // Requires:      memmap.h
46 // Provides:      create_memory_region()
47 //                delete_memory_region()
48 //                edit_memory_region()
49 //                create_memory_section()
50 //                delete_memory_section()
51 //                edit_memory_section()
52 //                delete_all_memory_sections()
53 //                set_map_size()
54 //                section_list
55 //                region_list
56 // See also:      memmap.h
57 // Known bugs:    <UPDATE_ME_AT_RELEASE_TIME>
58 // WARNING:       Do not modify data structures other than by using the
59 //                provided functions
60 // Usage:         #include "memmap.h"
61 //                ...
62 //                status = set_map_size (0x8000);
63 //
64 //####DESCRIPTIONEND####
65
66 #pragma warning (disable:4514) /* unreferenced inline function */
67 #pragma warning (disable:4710) /* function not inlined */
68
69 // Includes other headers for precompiled compilation
70 #include "ecpch.h"
71
72 #ifdef __BORLANDC__
73 #pragma hdrstop
74 #endif
75
76 #include "memmap.h"
77
78 using namespace std;
79
80 //////////////////////////////////////////////////////////////////////
81 // Construction/Destruction
82 //////////////////////////////////////////////////////////////////////
83
84 mem_map::mem_map()
85 {
86         map_modified_flag = true;
87         map_size = (mem_address) 0;
88 }
89
90 mem_map::~mem_map()
91 {
92
93 }
94
95 mem_section::mem_section()
96 {
97
98 }
99
100 mem_section::~mem_section()
101 {
102
103 }
104
105 ///////////////////////////////////////////////////////////////////////
106 // get_memory_region() retrieves the parameters of a memory region
107
108 bool mem_map::get_memory_region (std::string region_name, mem_address * region_address, mem_address * region_size, mem_type * region_type, std::string * note)
109 {
110     for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end (); ++region)
111         if (region->name == region_name)
112         {
113             *region_address = region->address;
114             *region_size = region->size;
115             *region_type = region->type;
116             *note = region->note;
117             return true;
118         }
119
120     return false;
121 }
122
123
124 ///////////////////////////////////////////////////////////////////////
125 // create_memory_region() inserts a new item into the memory region list
126 // in order of memory address
127
128 int mem_map::create_memory_region (std::string new_region_name, mem_address new_region_address, mem_address new_region_size, mem_type new_region_type, std::string note)
129 {
130     const mem_address new_region_end = new_region_address + new_region_size; // the byte after the new region end
131
132     // check that the new region name is specified
133
134     if (new_region_name == "")
135         return ERR_MEMMAP_REGION_NONAME; // the new region name must be specified
136
137     // check that the new region lies within the memory map
138
139     if (new_region_end > map_size)
140         return ERR_MEMMAP_REGION_MAPSIZE; // the new region does not lie within the memory map
141
142     // check that the region end address hasn't exceeded the storage size
143
144     if (new_region_end < new_region_address)
145         return ERR_MEMMAP_REGION_MAPSIZE; // the new region does not lie within the memory map
146
147     // initialise the insertion point for the new region
148
149     list <mem_region>::iterator insertion_point = region_list.end ();
150
151     // check that the new region does not overlap existing regions and does not already exist
152
153     for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end (); ++region)
154     {
155         const mem_address region_end = region->address + region->size; // the byte after the region end
156
157         if ((new_region_address >= region->address) && (new_region_address < region_end))
158         {
159             error_info = region->name;
160             return ERR_MEMMAP_REGION_INTERSECT; // the start of the new region is within an existing region
161         }
162
163         if ((new_region_end > region->address) && (new_region_end <= region_end))
164         {
165             error_info = region->name;
166             return ERR_MEMMAP_REGION_INTERSECT; // the end of the new region is within an existing region
167         }
168
169         if ((new_region_address < region->address) && (new_region_end > region_end))
170         {
171             error_info = region->name;
172             return ERR_MEMMAP_REGION_INTERSECT; // an existing region lies within the new region
173         }
174
175         if (region->name == new_region_name)
176             return ERR_MEMMAP_REGION_NAMEINUSE; // the new region name is not unique
177
178         if ((insertion_point == region_list.end ()) && (region->address > new_region_address))
179             insertion_point = region; // insert the new region here
180     }
181
182     // add the new region to the region list
183
184     list <mem_region>::iterator new_region = region_list.insert (insertion_point);
185     new_region->name = new_region_name;
186     new_region->address = new_region_address;
187     new_region->size = new_region_size;
188     new_region->type = new_region_type;
189     new_region->note = note;
190
191     // initialise the section list for the new region
192
193     calc_section_list (new_region);
194
195         map_modified_flag = true;
196     return 0;
197 }
198
199
200 ///////////////////////////////////////////////////////////////////////
201 // edit_memory_region() edits an item in the memory region list
202
203 int mem_map::edit_memory_region (std::string old_region_name, std::string new_region_name, mem_address new_region_address, mem_address new_region_size, mem_type new_region_type, std::string note)
204 {
205     list <mem_region>::iterator edit_region = find_memory_region (old_region_name);
206     if (edit_region == NULL)
207         return ERR_MEMMAP_REGION_NOTFOUND; // the region to be modified does not exist
208
209     // check that the new region name is specified
210
211     if (new_region_name == "")
212         return ERR_MEMMAP_REGION_NONAME; // the new region name must be specified
213
214     // check that the region end address hasn't exceeded the storage size
215
216     if (new_region_address + new_region_size < new_region_address)
217         return ERR_MEMMAP_REGION_MAPSIZE; // the new region does not lie within the memory map
218
219     // check region name change
220
221     if ((old_region_name != new_region_name) &&
222         (find_memory_region (new_region_name) != NULL))
223         return ERR_MEMMAP_REGION_NAMEINUSE; // new region name is not unique
224
225     // check region address/size change wrt other regions
226
227     const mem_address new_region_end = new_region_address + new_region_size;
228     if ((new_region_address != edit_region->address) ||
229         (new_region_size != edit_region->size))
230     {
231         for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end (); ++region)
232             if (region != edit_region)
233         {
234             const mem_address region_end = region->address + region->size; // the byte after the region end
235
236             if ((new_region_address >= region->address) && (new_region_address < region_end))
237             {
238                 error_info = region->name;
239                 return ERR_MEMMAP_REGION_INTERSECT; // the start of the modified region is within another region
240             }
241
242             if ((new_region_end > region->address) && (new_region_end <= region_end))
243             {
244                 error_info = region->name;
245                 return ERR_MEMMAP_REGION_INTERSECT; // the end of the modified region is within an existing region
246             }
247
248             if ((new_region_address < region->address) && (new_region_end > region_end))
249             {
250                 error_info = region->name;
251                 return ERR_MEMMAP_REGION_INTERSECT; // another region lies within the modified region
252             }
253         }
254     }
255
256     // check region size change wrt sections within region (if any)
257
258     for (list <mem_section_view>::iterator section_view = edit_region->section_view_list.begin (); section_view != edit_region->section_view_list.end (); ++section_view)
259         if (section_view->section != NULL)
260     {
261         if ((section_view->section_location == final_location) || (section_view->section_location == fixed_location))
262             if (section_view->section->final_location->anchor == absolute)
263                 if (section_view->section->final_location->address + section_view->section->size - edit_region->address > new_region_size)
264                     return ERR_MEMMAP_REGION_SIZE; // region is now too small
265
266         if (section_view->section_location == initial_location)
267             if (section_view->section->initial_location->anchor == absolute)
268                 if (section_view->section->initial_location->address + section_view->section->size - edit_region->address > new_region_size)
269                     return ERR_MEMMAP_REGION_SIZE; // region is now too small
270     }
271
272     // check region read-only change FIXME
273
274     // move sections within the region having absolute anchors
275
276     for (section_view = edit_region->section_view_list.begin (); section_view != edit_region->section_view_list.end (); ++section_view)
277         if (section_view->section != NULL)
278     {
279         if ((section_view->section_location == final_location) || (section_view->section_location == fixed_location))
280             if (section_view->section->final_location->anchor == absolute)
281                 section_view->section->final_location->address += (new_region_address - edit_region->address);
282
283         if ((section_view->section_location == initial_location) || (section_view->section_location == fixed_location))
284             if (section_view->section->initial_location->anchor == absolute)
285                 section_view->section->initial_location->address += (new_region_address - edit_region->address);
286     }
287
288     // deleteZ(the region and recreate it to make sure the region list is ordered correctly)
289
290     region_list.erase (edit_region);
291     if (create_memory_region (new_region_name, new_region_address, new_region_size, new_region_type, note))
292         return ERR_MEMMAP_ALLOC;
293
294         map_modified_flag = true;
295     return 0;
296 }
297
298
299 //////////////////////////////////////////////////////////////////
300 // delete_memory_region() removes an existing item from the memory
301 // region list
302
303 bool mem_map::delete_memory_region (std::string name)
304 {
305     // make sure that there are no used sections in this region before deleting it
306
307     for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end (); ++region)
308     {
309         if ((region->name == name) && (region->section_view_list.size () == 1) &&  (region->section_view_list.front ().section == NULL))
310         {
311             region_list.erase (region);
312                         map_modified_flag = true;
313             return true;
314         }
315     }
316
317     return false;
318 }
319
320 ///////////////////////////////////////////////////////////////////
321 // set_map_size() sets the maximum permitted address for the end
322 // of any memory region
323
324 bool mem_map::set_map_size (mem_address new_map_size)
325 {
326     // check that the new size is sufficient for all previously defined memory regions
327
328     for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end (); ++region)
329     {
330         if (region->address + region->size > new_map_size)
331             return false; // the new map size is too small
332     }
333
334     // set the map size
335
336     map_size = new_map_size;
337
338     return true;
339 }
340
341
342 ////////////////////////////////////////////////////////////////////
343 // edit_memory_section() edits an item to the memory section map
344
345 int mem_map::edit_memory_section (std::string old_section_name, std::string new_section_name, mem_address section_size, mem_address section_alignment, mem_anchor initial_section_anchor, std::string initial_anchor_section_name, mem_address initial_anchor_address, mem_anchor final_section_anchor, std::string final_anchor_section_name, mem_address final_anchor_address, bool relocates, bool anchor_to_initial_location, bool linker_defined, std::string note)
346 {
347     // do all the parameter validation
348
349     if (new_section_name == "") // the new section name must be specified
350         return ERR_MEMMAP_SECTION_NONAME;
351
352     if ((new_section_name != old_section_name) &&
353         (find_memory_section (new_section_name) != NULL))
354         return ERR_MEMMAP_SECTION_NAMEINUSE; // the new section name is not unique
355
356     list <mem_section>::iterator section = find_memory_section (old_section_name);
357     if (section == NULL)
358         return ERR_MEMMAP_SECTION_NOTFOUND; // the specified old section name could not be found
359
360     // check that the LMA (if absolute) is within a memory region
361
362     list <mem_region>::iterator region;
363     if (initial_section_anchor == absolute)
364     {
365         region = find_region_by_address (initial_anchor_address);
366         if (region == NULL)
367             return ERR_MEMMAP_SECTION_LMA_NOTINREGION; // section LMA is not within a memory region
368         if ((section_size > 0) && (initial_anchor_address + section_size > region->address + region->size))
369             return ERR_MEMMAP_SECTION_LMA_NOTINREGION; // end of section is not within the memory region
370         if (relocates && (region->type == read_write))
371             return ERR_MEMMAP_SECTION_LMA_READWRITE; // section LMA must be in a read-only memory region
372     }
373
374     // check that the VMA (if absolute) is within a memory region
375
376     if (final_section_anchor == absolute)
377     {
378         region = find_region_by_address (final_anchor_address);
379         if (region == NULL)
380             return ERR_MEMMAP_SECTION_VMA_NOTINREGION; // section VMA is not within a memory region
381         if ((section_size > 0) && (final_anchor_address + section_size > region->address + region->size))
382             return ERR_MEMMAP_SECTION_VMA_NOTINREGION; // end of section is not within the memory region
383         if (relocates && (region->type == read_only))
384             return ERR_MEMMAP_SECTION_VMA_READONLY; // section VMA must be in a read/write memory region
385     }
386
387     // check relative location information as appropriate
388
389     if (relocates) // only check the initial parent section if the section relocates
390     {
391         if (initial_section_anchor == relative)
392         {
393             list <mem_section>::iterator parent_section = find_memory_section (initial_anchor_section_name);
394             if (parent_section == section_list.end ())
395                 return ERR_MEMMAP_SECTION_LMA_ANCHORNOTFOUND; // initial anchor name not found
396
397             if ((parent_section->initial_location->following_section != section) && (parent_section->initial_location->following_section != NULL))
398                 return ERR_MEMMAP_SECTION_LMA_ANCHORNOTAVAIL; // initial anchor specified has changed and is unavailable
399
400             if ((parent_section->size == 0) && (! parent_section->linker_defined))
401                 return ERR_MEMMAP_SECTION_LMA_ANCHORNOTAVAIL; // initial anchor specified expands to fit available space
402
403             if (find_region_by_section (parent_section, initial_location)->type == read_write)
404                 return ERR_MEMMAP_SECTION_LMA_READWRITE; // initial anchor must be in a read-only memory region
405         }
406     }
407
408     if (final_section_anchor == relative)
409     {
410         list <mem_section>::iterator parent_section = find_memory_section (final_anchor_section_name);
411         if (parent_section == NULL)
412             return ERR_MEMMAP_SECTION_VMA_ANCHORNOTFOUND; // final anchor name not found
413
414         if ((parent_section->size == 0) && (! parent_section->linker_defined))
415             return ERR_MEMMAP_SECTION_VMA_ANCHORNOTAVAIL; // final anchor specified expands to fit available space
416
417         if ((!relocates) && anchor_to_initial_location) // final anchor to initial location of parent section
418         {
419             if ((parent_section->initial_location->following_section != section) && (parent_section->initial_location->following_section != NULL))
420                 return ERR_MEMMAP_SECTION_VMA_ANCHORNOTAVAIL; // final anchor specified has changed and is unavailable
421         }
422         else
423         {
424             if ((parent_section->final_location->following_section != section) && (parent_section->final_location->following_section != NULL))
425                 return ERR_MEMMAP_SECTION_VMA_ANCHORNOTAVAIL; // final anchor specified has changed and is unavailable
426         }
427
428         if (relocates && (find_region_by_section (parent_section, final_location)->type == read_only))
429             return ERR_MEMMAP_SECTION_VMA_READONLY; // final anchor of relocating section must be in a read/write memory region
430     }
431
432         // check for a non-relocating section changing to relocating where the final
433         // location moves from a read_only region to a read_write region and there
434         // is a following non-relocating section
435
436     if (relocates && (! section->relocates) &&
437                 (find_region_by_section (section, fixed_location)->type == read_only) &&
438                 (section->final_location->following_section != NULL) &&
439                 (! section->final_location->following_section->relocates))
440         {
441                 return ERR_MEMMAP_SECTION_ILLEGAL_RELOCATION;
442         }
443
444     // FIXME check for overlap of absolute sections
445
446     // modify the initial section location data
447
448     if (section->initial_location->anchor == relative) // initial section anchor was relative
449         find_preceding_section (section, true)->initial_location->following_section = NULL;
450
451     if (initial_section_anchor == absolute) // initial location now absolute
452         section->initial_location->address = initial_anchor_address;
453     else // initial location now relative
454     {
455         list <mem_section>::iterator initial_parent = find_memory_section (initial_anchor_section_name);
456         if (relocates || (! initial_parent->relocates))
457             initial_parent->initial_location->following_section = section;
458     }
459
460     // modify the final section location data
461
462     if (section->final_location->anchor == relative) // final section anchor was relative
463         find_preceding_section (section, false)->final_location->following_section = NULL;
464
465     if (final_section_anchor == absolute) // final location now absolute
466         section->final_location->address = final_anchor_address;
467     else // final location now relative
468     {
469         list <mem_section>::iterator final_parent = find_memory_section (final_anchor_section_name);
470         final_parent->final_location->following_section = section;
471     }
472
473     // handle relocation changes
474
475     if (relocates && (! section->relocates)) // section was non-relocating but now relocates
476         {
477                 if (find_region_by_section (section, fixed_location)->type == read_only) // the section was in a read_only region
478                    section->final_location->following_section = NULL; // there is now no section following the final location
479                 else
480                    section->initial_location->following_section = NULL; // there is now no section following the initial location
481         }
482
483     else if ((! relocates) && section->relocates) // section was relocating but is now non-relocating
484         {
485                 // determine the type of memory region in which the section now resides
486
487                 mem_type type;
488                 if ((final_section_anchor == relative) && anchor_to_initial_location)
489                         type = find_region_by_section (find_memory_section (final_anchor_section_name), initial_location)->type;
490                 else if (final_section_anchor == relative) // anchored to final location of preceding section
491                         type = find_region_by_section (find_memory_section (final_anchor_section_name), final_location)->type;
492                 else // final_section_anchor must be absolute
493                         type = find_region_by_address (final_anchor_address)->type;
494
495                 if (type == read_only) // the section is now in a read-only memory region
496                 {
497                         if ((section->initial_location->following_section != NULL) && ! section->initial_location->following_section->relocates)
498                                 section->final_location->following_section = section->initial_location->following_section;
499                         else
500                                 section->final_location->following_section = NULL;
501                 }
502                 else // the section is now in a read-write memory region
503                 {
504                         if ((section->final_location->following_section != NULL) && ! section->final_location->following_section->relocates)
505                                 section->initial_location->following_section = section->final_location->following_section;
506                         else
507                                 section->initial_location->following_section = NULL;
508                 }
509         }
510
511     // modify the remaining section data
512
513     section->name = new_section_name;
514     section->size = section_size;
515     section->alignment = section_alignment;
516     section->relocates = relocates;
517     section->note = note;
518     section->linker_defined = linker_defined;
519     section->initial_location->anchor = initial_section_anchor;
520     section->final_location->anchor = final_section_anchor;
521
522     // recalculate section lists for all regions
523
524     calc_section_lists ();
525
526         map_modified_flag = true;
527     return 0;
528 }
529
530
531 ////////////////////////////////////////////////////////////////////
532 // create_memory_section() adds a new item to the memory section map
533 // either a section name (for relative locations) or an anchor address
534 // (for absolute locations) must be specified
535
536 int mem_map::create_memory_section (std::string section_name, mem_address section_size, mem_address section_alignment, mem_anchor initial_section_anchor, std::string initial_anchor_section_name, mem_address initial_anchor_address, mem_anchor final_section_anchor, std::string final_anchor_section_name, mem_address final_anchor_address, bool relocates, bool anchor_to_initial_location, bool linker_defined, std::string note)
537 {
538     list <mem_region>::iterator region;
539
540     // check that the new section name is specified
541
542     if (section_name == "")
543         return ERR_MEMMAP_SECTION_NONAME; // the new section name must be specified
544     
545     // check that the new section name is unique
546
547     if (find_memory_section (section_name) != NULL)
548         return ERR_MEMMAP_SECTION_NAMEINUSE; // the new section name is not unique
549
550     // check that the LMA (if absolute) is within a memory region
551
552     if (initial_section_anchor == absolute)
553     {
554         region = find_region_by_address (initial_anchor_address);
555         if (region == NULL)
556             return ERR_MEMMAP_SECTION_LMA_NOTINREGION; // section LMA is not within a memory region
557         if ((section_size > 0) && (initial_anchor_address + section_size > region->address + region->size))
558             return ERR_MEMMAP_SECTION_LMA_NOTINREGION; // end of section is not within the memory region
559         if (relocates && (region->type == read_write))
560             return ERR_MEMMAP_SECTION_LMA_READWRITE; // section LMA must be in a read-only memory region
561     }
562
563     // check that the VMA (if absolute) is within a memory region
564
565     if (final_section_anchor == absolute)
566     {
567         region = find_region_by_address (final_anchor_address);
568         if (region == NULL)
569             return ERR_MEMMAP_SECTION_VMA_NOTINREGION; // section VMA is not within a memory region
570         if ((section_size > 0) && (final_anchor_address + section_size > region->address + region->size))
571             return ERR_MEMMAP_SECTION_VMA_NOTINREGION; // end of section is not within the memory region
572         if (relocates && (region->type == read_only))
573             return ERR_MEMMAP_SECTION_VMA_READONLY; // section VMA must be in a read/write memory region
574     }
575
576     // FIXME check for overlap of absolute sections
577
578     // check that specified parent(s) (for relative anchors) are available
579
580     if (relocates) // only check the initial parent section if the section relocates
581     {
582         if (initial_section_anchor == relative)
583         {
584             list <mem_section>::iterator parent_section = find_memory_section (initial_anchor_section_name);
585             if (parent_section == section_list.end ())
586                 return ERR_MEMMAP_SECTION_LMA_ANCHORNOTFOUND; // initial anchor name not found
587 /*
588             if (parent_section->initial_location->following_section != NULL)
589                 return ERR_MEMMAP_SECTION_LMA_ANCHORNOTAVAIL; // initial anchor specified is unavailable
590 */
591             if ((parent_section->size == 0) && (! parent_section->linker_defined))
592                 return ERR_MEMMAP_SECTION_LMA_ANCHORNOTAVAIL; // initial anchor specified expands to fit available space
593
594             if (find_region_by_section (parent_section, initial_location)->type == read_write)
595                 return ERR_MEMMAP_SECTION_LMA_READWRITE; // initial anchor must be in a read-only memory region
596         }
597     }
598
599     if (final_section_anchor == relative)
600     {
601         list <mem_section>::iterator parent_section = find_memory_section (final_anchor_section_name);
602         if (parent_section == NULL)
603             return ERR_MEMMAP_SECTION_VMA_ANCHORNOTFOUND; // final anchor name not found
604
605         if ((parent_section->size == 0) && (! parent_section->linker_defined))
606             return ERR_MEMMAP_SECTION_VMA_ANCHORNOTAVAIL; // final anchor specified expands to fit available space
607 /*
608         if ((!relocates) && anchor_to_initial_location) // final anchor to initial location of parent section
609         {
610             if (parent_section->initial_location->following_section != NULL)
611                 return ERR_MEMMAP_SECTION_VMA_ANCHORNOTAVAIL; // final anchor specified is unavailable
612         }
613         else
614         {
615             if (parent_section->final_location->following_section != NULL)
616                 return ERR_MEMMAP_SECTION_VMA_ANCHORNOTAVAIL; // final anchor specified is unavailable
617         }
618 */
619         if (relocates && (find_region_by_section (parent_section, final_location)->type == read_only))
620             return ERR_MEMMAP_SECTION_VMA_READONLY; // final anchor of relocating section must be in a read/write memory region
621     }
622
623     // add the new section to the section map
624
625     mem_section new_mem_section;
626     list <mem_section>::iterator new_section = section_list.insert (section_list.begin (), new_mem_section);
627     new_section->name = section_name;
628     new_section->size = section_size;
629     new_section->alignment = section_alignment;
630     new_section->relocates = relocates;
631     new_section->note = note;
632     new_section->linker_defined = linker_defined;
633     new_section->initial_location = new mem_location;
634     new_section->final_location = new mem_location;
635     new_section->initial_location->following_section = NULL; // initialize struct
636     new_section->final_location->following_section = NULL; // initialize struct
637     new_section->initial_location->anchor = initial_section_anchor;
638     new_section->final_location->anchor = final_section_anchor;
639
640     if ((initial_section_anchor == relative) &&
641         (!relocates) && (find_memory_section (initial_anchor_section_name)->relocates))
642     {
643         // a non-relocating relative section anchored to a relocating section
644
645         if (anchor_to_initial_location) // new section is anchored to the initial location of a relocating section
646         {
647             list <mem_section>::iterator anchor_section = find_memory_section (initial_anchor_section_name);
648             new_section->initial_location->following_section = anchor_section->initial_location->following_section;
649             anchor_section->initial_location->following_section = new_section;
650         }
651         else // new section is anchored to the final location of a relocating section
652         {
653             list <mem_section>::iterator anchor_section = find_memory_section (initial_anchor_section_name);
654             new_section->final_location->following_section = anchor_section->final_location->following_section;
655             anchor_section->final_location->following_section = new_section;
656         }
657     }
658     else
659     {
660         // copy initial location data
661
662         if (initial_section_anchor == relative) // new section follows the named anchor section
663         {
664             list <mem_section>::iterator anchor_section = find_memory_section (initial_anchor_section_name);
665             new_section->initial_location->following_section = anchor_section->initial_location->following_section; // move anchor of the following section
666             anchor_section->initial_location->following_section = new_section; // anchor the new section
667         }
668         else // new section has an absolute anchor
669             new_section->initial_location->address = initial_anchor_address;
670     
671         // copy final location data
672
673         if (final_section_anchor == relative) // new section follows the named anchor section
674         {
675             list <mem_section>::iterator anchor_section = find_memory_section (final_anchor_section_name);
676             new_section->final_location->following_section = anchor_section->final_location->following_section; // move anchor of the following section
677             anchor_section->final_location->following_section = new_section; // anchor the new section
678         }
679         else // new section has an absolute anchor
680             new_section->final_location->address = final_anchor_address;
681     }
682
683     // recalculate section lists for all regions
684
685     calc_section_lists ();
686
687         map_modified_flag = true;
688     return 0;
689 }
690
691
692 ////////////////////////////////////////////////////////////////////////
693 // calc_section_lists() updates the lists of memory sections for all
694 // memory regions
695
696 bool mem_map::calc_section_lists ()
697 {
698     for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end(); ++region)
699         calc_section_list (region);
700
701     return true;
702 }
703
704
705 ////////////////////////////////////////////////////////////////////////
706 // calc_section_list() updates the list of memory sections which reside 
707 // in the specified memory region. It is called whenever the section
708 // map is modified.
709
710 bool mem_map::calc_section_list (list <mem_region>::iterator region)
711 {
712     // clear the old list (if any)
713
714         //TRACE (_T("Calculating section list for region '%s'\n"), CString (region->name.c_str()));
715     region->section_view_list.clear ();
716
717     // add the initial and final locations of each absolute section as necessary
718
719     for (list <mem_section>::iterator section = section_list.begin (); section != section_list.end (); ++section)
720     {
721         if (section->relocates) // the section is relocated and must be added to the view twice
722         {
723             add_absolute_section_to_list (region, section, initial_location);
724             add_absolute_section_to_list (region, section, final_location);
725         }
726         else // the section is not relocated and must be added to the view once only
727             add_absolute_section_to_list (region, section, fixed_location);
728     }
729
730     // add unused sections to section view list where appropriate
731
732     list <mem_section_view>::iterator previous_section_view = region->section_view_list.begin ();
733
734     if (previous_section_view == region->section_view_list.end ()) // no used sections in this region
735     {
736         // add a single unused section to the section view list
737
738         mem_section_view new_section_view;
739         new_section_view.section = NULL; // an unused section
740         region->section_view_list.push_back (new_section_view); // add to the section list for this region
741     }
742     else // there are used sections in this region
743     {
744         list <mem_section_view>::iterator second_section_view = region->section_view_list.begin ();
745         ++second_section_view;
746
747         // add unused sections between used sections where they do not meet in either initial or final locations
748
749         for (list <mem_section_view>::iterator section_view = second_section_view; section_view != region->section_view_list.end (); ++section_view)
750         {
751             if (! (absolute_sections_meet (previous_section_view->section, section_view->section)))
752             {
753                 list <mem_section_view>::iterator new_section_view = region->section_view_list.insert (section_view); // add an unused section
754                 new_section_view->section = NULL;
755             }
756
757             previous_section_view = section_view;
758         }
759
760         // add an unused section to end of region if the last section does not reach the end of the region in initial or final locations
761
762         if (! at_end_of_region (region->section_view_list.back().section, region))
763         {
764             mem_section_view new_section_view;
765             new_section_view.section = NULL; // an unused section
766             region->section_view_list.push_back (new_section_view); // add an unused section
767         }
768
769         // add an unused section to start of region if the first section does not start at the start of the region in initial or final locations
770
771         if (! at_start_of_region (region->section_view_list.front().section, region))
772         {
773             mem_section_view new_section_view;
774             new_section_view.section = NULL; // an unused section
775             region->section_view_list.push_front (new_section_view); // add an unused section
776         }
777     }
778
779     // add the initial and final locations of the each relative section as necessary
780
781     for (list <mem_section_view>::iterator section_view = region->section_view_list.begin (); section_view != region->section_view_list.end (); ++section_view)
782         if (section_view->section != NULL) // if section is used
783     {
784         list <mem_section>::iterator section = section_view->section;
785 /*
786                 TRACE (_T("Calculating relative sections for section view '%s' %s\n"), CString (section->name.c_str ()),
787                         section_view->section_location == final_location ? _T("(final)") :
788                         section_view->section_location == initial_location ? _T("(initial)") : _T("(fixed)"));
789 */
790
791         if (section_view->section_location == final_location)
792         {
793             if (section->final_location->anchor == absolute)
794                 add_relative_sections_to_list (region, section_view, final_location);            
795         }
796
797         else if (section_view->section_location == initial_location)
798         {
799             if (section->initial_location->anchor == absolute)
800                 add_relative_sections_to_list (region, section_view, initial_location);
801         }
802
803         else // section_view->section_location == fixed_location
804         {
805             if (section->initial_location->anchor == absolute)
806                 add_relative_sections_to_list (region, section_view, initial_location);
807             if (section->final_location->anchor == absolute)
808                 add_relative_sections_to_list (region, section_view, final_location);
809         }
810     }
811
812     // remove unused sections where user-defined section of unknown size will be placed
813
814     section_view = region->section_view_list.begin ();
815     while (section_view != region->section_view_list.end ())
816     {
817         bool expanding_section = false;
818         if ((section_view->section != NULL) &&
819             (section_view->section->size == 0) &&
820             (! section_view->section->linker_defined))
821             expanding_section = true;
822
823         ++section_view;
824
825         if (expanding_section && (section_view != region->section_view_list.end ()) && (section_view->section == NULL))
826             section_view = region->section_view_list.erase (section_view);
827     }
828
829     return true;
830 }
831
832 /////////////////////////////////////////////////////////////////////
833 // add_relative_sections_to_list() inserts the sections defined relative
834 // to the specified section list item to the section list for the
835 // specified region in the appropriate order
836
837 bool mem_map::add_relative_sections_to_list (list <mem_region>::iterator region, list <mem_section_view>::iterator section_view, section_location_type location_type)
838 {
839     // insert following relative sections of type 'location_type' in region_view.section_view_list
840
841     list <mem_section>::iterator new_section = section_view->section;
842     mem_location * new_section_location = (location_type == initial_location ? new_section->initial_location : new_section->final_location);
843     list <mem_section_view>::iterator insertion_point = section_view;
844     ++insertion_point;
845     bool no_relocation = true;
846
847     while (new_section_location->following_section != NULL)
848     {
849         // add the new section to the section view list
850
851         mem_section_view new_section_view;
852         new_section_view.section = new_section_location->following_section;
853                 const bool section_relocates = new_section->relocates;
854         new_section = new_section_view.section;
855         new_section_view.section_location = (new_section->relocates ? location_type : fixed_location);
856         if ((new_section_view.section_location == fixed_location) && (location_type == final_location) && (! section_view->section->relocates) && (! section_relocates) && no_relocation)
857         {
858             // section already added to the view so add nothing but
859             // increment insertion point for following sections
860             // TRACE (_T("Skipping section %s %s location (relative) preceding %s\n"), CString (new_section_location->following_section->name.c_str()), location_type == initial_location ? _T("initial") : _T("final"), ((insertion_point != region->section_view_list.end ()) && (insertion_point->section != NULL)) ? CString (insertion_point->section->name.c_str()) : _T("(null)"));
861             ++insertion_point;
862         }
863         else
864         {
865             // TRACE (_T("Inserting section %s %s location (relative) preceding %s\n"), CString (new_section_location->following_section->name.c_str()), location_type == initial_location ? _T("initial") : _T("final"), ((insertion_point != region->section_view_list.end ()) && (insertion_point->section != NULL)) ? CString (insertion_point->section->name.c_str()) : _T("(null)"));
866             region->section_view_list.insert (insertion_point, new_section_view);
867             no_relocation = no_relocation && ! new_section_view.section->relocates;
868         }
869         new_section_location = (location_type == initial_location ? new_section->initial_location : new_section->final_location);
870     }    
871
872     return true;
873 }
874
875 /////////////////////////////////////////////////////////////////////
876 // add_absolute_section_to_list() inserts the specified section to the
877 // specified section list at the appropriate place if it has an
878 // absolute location and that location is within the specified memory
879 // region
880
881 bool mem_map::add_absolute_section_to_list (list <mem_region>::iterator region, list <mem_section>::iterator additional_section, section_location_type location_type)
882 {
883     // get location of new section
884     mem_location * new_section_location = (location_type == initial_location ? additional_section->initial_location : additional_section->final_location);
885
886     if ((new_section_location->anchor == absolute) && (new_section_location->address >= region->address) && (new_section_location->address < region->address + region->size))
887         {
888         // the section lies in the region
889
890         // initialise the insertion point for the new section
891         list <mem_section_view>::iterator insertion_point = region->section_view_list.end ();
892
893         for (list <mem_section_view>::iterator section = region->section_view_list.begin (); section != region->section_view_list.end (); ++section)
894         {
895             // get location of section
896             mem_location * section_location  = (section->section_location == initial_location ? section->section->initial_location : section->section->final_location);
897
898             // compare with location of new section
899             if ((new_section_location->anchor == absolute) && (section_location->address >= new_section_location->address))
900             {
901                 // insert new section here if the current section has a higher address
902                 insertion_point = section;
903                 break;
904             }
905         }
906
907         // add the new section to the section view list
908
909                 // TRACE (_T("Inserting section %s %s location (absolute) preceding %s\n"), CString (additional_section->name.c_str()), location_type == initial_location ? _T("initial") : _T("final"), insertion_point != region->section_view_list.end () ? CString (insertion_point->section->name.c_str()) : _T("(end)"));
910         mem_section_view new_section_view;
911         new_section_view.section = additional_section;
912         new_section_view.section_location = location_type;
913         region->section_view_list.insert (insertion_point, new_section_view);
914     }
915
916     return true;
917 }
918
919
920 ////////////////////////////////////////////////////////////////////
921 // absolute_sections_meet() determines whether the specified
922 // absolute memory sections meet. It assumes that section2 comes
923 // after section1 in the memory map.
924
925 bool mem_map::absolute_sections_meet(list <mem_section>::iterator section1, list <mem_section>::iterator section2)
926 {
927     if (section1->size == 0) // size of section1 is unknown
928         return false;
929
930     // check if initial section locations meet
931
932     if ((section1->initial_location->anchor == absolute) && 
933         ((section2->initial_location->anchor == absolute) &&
934         section1->initial_location->address + section1->size == section2->initial_location->address))
935         return true;
936
937     // check if final section locations meet
938
939     if ((section1->final_location->anchor == absolute) && 
940         ((section2->final_location->anchor == absolute) &&
941         section1->final_location->address + section1->size == section2->final_location->address))
942         return true;
943
944     return false;
945 }
946
947
948 //////////////////////////////////////////////////////////////
949 // at_start_of_region() determines whether the specified section
950 // is located at the very start of the specified region
951
952 bool mem_map::at_start_of_region (list <mem_section>::iterator section, list <mem_region>::iterator region)
953 {
954     // check initial section location
955     
956     if ((section->initial_location->anchor == absolute) &&
957         (section->initial_location->address == region->address))
958         return true;
959
960     // check final section location
961     
962     if ((section->final_location->anchor == absolute) &&
963         (section->final_location->address == region->address))
964         return true;
965
966     return false;
967 }
968
969 //////////////////////////////////////////////////////////////
970 // at_end_of_region() determines whether the specified section
971 // is located at the very end of the specified region
972
973 bool mem_map::at_end_of_region (list <mem_section>::iterator section, list <mem_region>::iterator region)
974 {
975     if (section->size == 0) // size of section is unknown
976         return false;
977
978     // check initial section location
979     
980     if ((section->initial_location->anchor == absolute) &&
981         section->initial_location->address + section->size == region->address + region->size)
982         return true;
983
984     // check final section location
985     
986     if ((section->final_location->anchor == absolute) &&
987         section->final_location->address + section->size == region->address + region->size)
988         return true;
989
990     return false;
991 }
992
993 ////////////////////////////////////////////////////////////////////////
994 // find_preceding_section() finds the preceding section in the
995 // memory section list
996
997 list <mem_section>::iterator mem_map::find_preceding_section (list <mem_section>::iterator reference_section, bool initial_location)
998 {
999     for (list <mem_section>::iterator section = section_list.begin (); section != section_list.end (); ++section)
1000     {
1001         if (reference_section == (reference_section->relocates && initial_location ? section->initial_location->following_section : section->final_location->following_section)) // if preceding section found
1002             return section; // return the section iterator
1003     }
1004     return NULL; // section not found
1005 }
1006
1007 ////////////////////////////////////////////////////////////////////////
1008 // find_memory_section() finds an existing section in the
1009 // memory section list
1010
1011 list <mem_section>::iterator mem_map::find_memory_section (std::string section_name)
1012 {
1013     for (list <mem_section>::iterator section = section_list.begin (); section != section_list.end (); ++section)
1014         if (section->name == section_name) // if section found
1015             return section; // return the section iterator
1016
1017     return NULL; // section not found
1018 }
1019
1020
1021 ////////////////////////////////////////////////////////////////////////
1022 // find_memory_region() finds an existing region in the
1023 // memory region list
1024
1025 list <mem_region>::iterator mem_map::find_memory_region (std::string region_name)
1026 {
1027     for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end (); ++region)
1028         if (region->name == region_name) // if region found
1029             return region; // return the region iterator
1030
1031     return NULL; // region not found
1032 }
1033
1034
1035 ////////////////////////////////////////////////////////////////////////
1036 // delete_memory_section() removes an existing item from the
1037 // memory section map
1038
1039 bool mem_map::delete_memory_section (std::string name)
1040 {
1041     // make sure that the section exists
1042
1043     list <mem_section>::iterator section = find_memory_section (name);
1044     if (section == NULL)
1045         return false; // there is no section with this name
1046
1047 /*
1048     // make sure that there are no sections defined relative to this section before deleting it
1049
1050     if (section->initial_location->following_section != NULL)
1051         return false;
1052
1053     if (section->final_location->following_section != NULL)
1054         return false;
1055 */
1056
1057     // if section is absolute, copy the initial and final location information to
1058     // the following sections (if any)
1059
1060     if ((section->initial_location->anchor == absolute) && (section->initial_location->following_section != NULL))
1061     {
1062         section->initial_location->following_section->initial_location->anchor = absolute;
1063         section->initial_location->following_section->initial_location->address = section->initial_location->address;
1064         // FIXME adjust new address of following section for alignment here
1065     }
1066
1067     if ((section->final_location->anchor == absolute) && (section->final_location->following_section != NULL))
1068     {
1069         section->final_location->following_section->final_location->anchor = absolute;
1070         section->final_location->following_section->final_location->address = section->final_location->address;
1071         // FIXME adjust new address of following section for alignment here
1072     }
1073
1074     // if section is relative, find the initial and final sections to which it is attached
1075     // and set their pointers to the sections following the one to be deleted (if any)
1076
1077     list <mem_section>::iterator related_section;
1078
1079     if (section->initial_location->anchor == relative)
1080         for (related_section = section_list.begin (); related_section != section_list.end (); ++related_section)
1081             if (related_section->initial_location->following_section == section)
1082                 related_section->initial_location->following_section = section->initial_location->following_section;
1083
1084     if (section->final_location->anchor == relative)
1085         for (related_section = section_list.begin (); related_section != section_list.end (); ++related_section)
1086             if (related_section->final_location->following_section == section)
1087                 related_section->final_location->following_section = section->final_location->following_section;
1088
1089     // delete the section
1090
1091     delete section->initial_location;
1092     section->initial_location = NULL;
1093
1094     delete section->final_location;
1095     section->final_location = NULL;
1096
1097     section_list.erase (section);
1098
1099     // recalculate section lists for all regions
1100
1101     calc_section_lists ();
1102
1103         map_modified_flag = true;
1104     return true;
1105 }
1106
1107
1108 ////////////////////////////////////////////////////////////////////////
1109 // delete_memory_sections() deletes all memory sections in preparation
1110 // for layout loading or application closure
1111
1112 bool mem_map::delete_all_memory_sections ()
1113 {
1114     // deleteZ(each section in turn)
1115
1116     while (section_list.size () > 0)
1117     {
1118         list <mem_section>::iterator section = section_list.begin ();
1119         delete section->initial_location;
1120         section->initial_location = NULL;
1121
1122         delete section->final_location;
1123         section->final_location = NULL;
1124
1125         section_list.erase (section);
1126     }
1127 //    section_list.clear ();
1128
1129     // recalculate section view lists for all regions
1130
1131     calc_section_lists ();
1132
1133         map_modified_flag = true;
1134     return true;
1135 }
1136
1137
1138 ////////////////////////////////////////////////////////////////////////
1139 // export_sections() exports section-related info for regions of the
1140 // specified type to the linker script fragment and header file
1141
1142 bool mem_map::export_sections (FILE * script_stream, FILE * header_stream, mem_type type)
1143 {
1144     for (list <mem_region>::iterator region = region_list.begin (); region != region_list.end(); ++region)
1145         if (region->type == type)
1146     {
1147         for (list <mem_section_view>::iterator section_view = region->section_view_list.begin (); section_view != region->section_view_list.end (); ++section_view)
1148         {
1149             if ((section_view->section != NULL) && (section_view->section_location != initial_location))
1150             {
1151                 if (section_view->section->linker_defined) // section is linker-defined
1152                 {
1153                     // output section name and region name
1154                     fprintf (script_stream, "    SECTION_%s (%s, ",
1155                         encode_section_name (section_view->section->name).c_str (), region->name.c_str ());
1156
1157                     // output VMA
1158                     if (section_view->section->final_location->anchor == absolute) // an absolute VMA
1159                         fprintf (script_stream, "%#lx, ", section_view->section->final_location->address); // specify absolute address
1160                     else // a relative VMA
1161                         fprintf (script_stream, "ALIGN (%#lx), ", section_view->section->alignment); // specify alignment
1162
1163                     // output LMA
1164                     if (! section_view->section->relocates) // section does not relocate so LMA == VMA
1165                         fprintf (script_stream, "LMA_EQ_VMA)");
1166                     else if (section_view->section->initial_location->anchor == absolute) // an absolute LMA
1167                         fprintf (script_stream, "AT (%#lx))", section_view->section->initial_location->address);
1168                     else // a relative LMA
1169                     {
1170                         list <mem_section>::iterator parent_section;
1171                         for (parent_section = section_list.begin (); parent_section != section_list.end (); ++parent_section)
1172                             if (parent_section->initial_location->following_section == section_view->section)
1173                                 break;
1174
1175                         if (parent_section->linker_defined) // parent section is linker-defined
1176                             fprintf (script_stream, "FOLLOWING (.%s))", parent_section->name.c_str ());
1177                         else // parent section is user-defined
1178                             fprintf (script_stream, "AT (__%s + %#lx))", parent_section->name.c_str (), parent_section->size);
1179                     }
1180                 }
1181                 else // section is user-defined
1182                 {
1183                     // output section symbol
1184                     if (section_view->section->final_location->anchor == absolute) // an absolute VMA
1185                         fprintf (script_stream, "    CYG_LABEL_DEFN(__%s) = %#lx;", section_view->section->name.c_str (), section_view->section->final_location->address);
1186                     else // a relative VMA
1187                         fprintf (script_stream, "    CYG_LABEL_DEFN(__%s) = ALIGN (%#lx);", section_view->section->name.c_str (), section_view->section->alignment);
1188
1189                     // update current location pointer
1190                     if (section_view->section->size != 0) // size is known
1191                         fprintf (script_stream, " . = CYG_LABEL_DEFN(__%s) + %#lx;", section_view->section->name.c_str (), section_view->section->size);
1192
1193                     // output reference to symbol in header file
1194                     fprintf (header_stream, "#ifndef __ASSEMBLER__\nextern char CYG_LABEL_NAME (__%s) [];\n#endif\n", section_view->section->name.c_str ());
1195                     fprintf (header_stream, "#define CYGMEM_SECTION_%s (CYG_LABEL_NAME (__%s))\n", section_view->section->name.c_str (), section_view->section->name.c_str ());
1196                     if (section_view->section->size == 0) // a section of unknown size
1197                     {
1198                         mem_address section_end_address;
1199
1200                         ++section_view; // move to next section_view
1201                         if (section_view == region->section_view_list.end ()) // section continues to end of region
1202                             section_end_address = region->address + region->size;
1203                         else // section continues to next section with an absolute location
1204                             section_end_address = section_view->section->final_location->address;
1205                         --section_view; // move back to previous section view
1206
1207                         fprintf (header_stream, "#define CYGMEM_SECTION_%s_SIZE (%#lx - (size_t) CYG_LABEL_NAME (__%s))\n", section_view->section->name.c_str (), section_end_address, section_view->section->name.c_str ());
1208                     }
1209                     else // a section of known size
1210                         fprintf (header_stream, "#define CYGMEM_SECTION_%s_SIZE (%#lx)\n", section_view->section->name.c_str (), section_view->section->size);
1211                 }
1212
1213                 // end of section description
1214
1215                 fprintf (script_stream, "\n"); // new line
1216             }
1217         }
1218     }
1219     return true;
1220 }
1221
1222
1223 ////////////////////////////////////////////////////////////////////////
1224 // export_files() creates a fragment of linker script and a header file
1225 // describing the memory layout
1226
1227 bool mem_map::export_files (const wxChar* script_name, const wxChar* header_name)
1228 {
1229     FILE * script_stream;
1230     FILE * header_stream;
1231     list <mem_region>::iterator region;
1232
1233         // do not export files if the memory layout is empty
1234         // assume that there are default LDI files available
1235
1236         if (region_list.size () == 0)
1237                 return false;
1238
1239     // open the script fragment file for writing
1240
1241     script_stream = _tfopen (script_name, _T("wt"));
1242     if (script_stream == NULL)
1243         return false;
1244
1245     // open the header file for writing
1246
1247     header_stream = _tfopen (header_name, _T("wt"));
1248     if (header_stream == NULL)
1249     {
1250         fclose (script_stream);
1251         return false;
1252     }
1253
1254     // output the linker script fragment header
1255
1256     time_t export_time;
1257     time (&export_time);
1258     struct tm * local = localtime (&export_time);
1259     fprintf (script_stream, "// eCos memory layout - %s\n%s\n\n", asctime (local), MLT_GENERATED_WARNING);
1260     fprintf (script_stream, "#include <cyg/infra/cyg_type.inc>\n\n");
1261
1262     // output the header file header
1263
1264     fprintf (header_stream, "// eCos memory layout - %s\n%s\n\n", asctime (local), MLT_GENERATED_WARNING);
1265         fprintf (header_stream, "#ifndef __ASSEMBLER__\n");
1266         fprintf (header_stream, "#include <cyg/infra/cyg_type.h>\n"); // for the CYG_LABEL_NAME macro definition
1267         fprintf (header_stream, "#include <stddef.h>\n\n"); // for size_t
1268         fprintf (header_stream, "#endif\n");
1269
1270     // output the MEMORY block
1271
1272     fprintf (script_stream, "MEMORY\n{\n"); // start of MEMORY block
1273     for (region = region_list.begin (); region != region_list.end(); ++region)
1274     {
1275         fprintf (script_stream, "    %s : ORIGIN = %#lx, LENGTH = %#lx\n", region->name.c_str(), region->address, region->size);
1276         fprintf (header_stream, "#define CYGMEM_REGION_%s (%#lx)\n", region->name.c_str(), region->address);
1277         fprintf (header_stream, "#define CYGMEM_REGION_%s_SIZE (%#lx)\n", region->name.c_str(), region->size);
1278         fprintf (header_stream, "#define CYGMEM_REGION_%s_ATTR (CYGMEM_REGION_ATTR_R%s)\n", region->name.c_str(), (read_write == region->type) ? " | CYGMEM_REGION_ATTR_W" : "");
1279     }
1280     fprintf (script_stream, "}\n\n"); // end of MEMORY block
1281
1282     // output the SECTIONS block
1283
1284     fprintf (script_stream, "SECTIONS\n{\n"); // start of SECTIONS block
1285     fprintf (script_stream, "    SECTIONS_BEGIN\n"); // SECTIONS block initial script macro call
1286     export_sections (script_stream, header_stream, read_only); // export sections in read-only regions first
1287     export_sections (script_stream, header_stream, read_write); // followed by sections in read-write regions
1288     fprintf (script_stream, "    SECTIONS_END\n"); // SECTIONS block final script macro call
1289     fprintf (script_stream, "}\n"); // end of SECTIONS block
1290
1291     // close the files
1292
1293     fclose (script_stream);
1294     fclose (header_stream);
1295
1296     return true;
1297 }
1298
1299
1300 ////////////////////////////////////////////////////////////////////////
1301 // import_linker_defined_sections() reads a the linker-defined section
1302 // names from the "SECTION_*" CPP macro definitions within the linker
1303 // script
1304
1305 bool mem_map::import_linker_defined_sections (const wxChar* filename)
1306 {
1307     // clear the linker-defined section name list
1308
1309     linker_defined_section_list.clear ();
1310
1311     // open the linker script file for reading
1312
1313     FILE * stream;
1314     stream = _tfopen (filename, _T("rt"));
1315     if (stream == NULL)
1316         return false;
1317
1318     bool macro = false; // not reading a CPP macro definition initially
1319     char input_string [32];
1320     while (! feof (stream))
1321     {
1322         if (macro)
1323         {
1324             if (fscanf (stream, "%8s", input_string) == EOF) // read the next 8 chars (not including whitespace)
1325                 break;
1326
1327             if (strcmp (input_string, "SECTION_") == 0) // an MLT section macro definition
1328             {
1329                 if (fscanf (stream, "%31[^(]", input_string) == EOF) // read the section name up to the '(' character
1330                     break;
1331
1332                 std::string section_name = decode_section_name (input_string);
1333                 if (find (linker_defined_section_list.begin (), linker_defined_section_list.end (), section_name) == linker_defined_section_list.end ()) // if section name is unique
1334                     linker_defined_section_list.push_back (section_name);
1335             }
1336
1337             macro = false;
1338         }
1339
1340         else
1341         {
1342             if (fscanf (stream, "%31s", input_string) == EOF)
1343                 break;
1344
1345             if (strcmp (input_string, "#define") == 0)
1346                 macro = true; // macro starts with "#define"
1347         }
1348
1349     }
1350
1351     // close the file
1352
1353     if (fclose (stream))
1354         return false;
1355
1356     return true;
1357 }
1358
1359 ////////////////////////////////////////////////////////////////////////
1360 // encode_note() encodes newlines in note
1361
1362 std::string mem_map::encode_note (std::string in)
1363 {
1364     std::string out = "!"; // dummy first character to ensure output string length > 0
1365
1366     for (unsigned int item = 0; item < in.size (); item++)
1367         if (in [item] == _TCHAR('\n')) // an LF character
1368             out += "\x07F"; // output substitution character 0x7F instead
1369         else if (in [item] != _TCHAR('\r')) // ignore the CR (present under Win32 only)
1370             out += in [item]; // copy other characters to output string unprocessed
1371
1372     return out;
1373 }
1374
1375 ////////////////////////////////////////////////////////////////////////
1376 // decode_note() decodes newlines in note
1377
1378 std::string mem_map::decode_note (std::string in)
1379 {
1380     std::string out;
1381
1382     for (unsigned int item = 1; item < in.size (); item++) // ignore dummy first character
1383         if (in [item] == _TCHAR('\x07F')) // the newline substitution character
1384             out += "\r\n"; // output CRLF instead
1385         else
1386             out += in [item];
1387
1388     return out;
1389 }
1390
1391 ////////////////////////////////////////////////////////////////////////
1392 // encode_section_name() encodes period -> double underscore in section name
1393
1394 std::string mem_map::encode_section_name (std::string in)
1395 {
1396     std::string out;
1397
1398     for (unsigned int item = 0; item < in.size (); item++)
1399         if (in [item] == '.') // a period character
1400                         out += "__"; // output a double underscore instead
1401         else
1402             out += in [item];
1403
1404     return out;
1405 }
1406
1407 ////////////////////////////////////////////////////////////////////////
1408 // decode_section_name() decodes double underscore -> period in section name
1409
1410 std::string mem_map::decode_section_name (std::string in)
1411 {
1412     std::string out;
1413
1414     for (unsigned int item = 0; item < in.size (); item++)
1415         if ((item + 1 < in.size ()) && (in [item] == '_') && (in [item + 1] == '_')) // two consecutive underscore characters
1416                 {
1417                         out += "."; // output a period instead
1418                         item++; // skip the second underscore
1419                 }
1420         else
1421             out += in [item];
1422
1423     return out;
1424 }
1425
1426 ////////////////////////////////////////////////////////////////////////
1427 // save_memory_layout() saves the memory layout to file for later use
1428
1429 bool mem_map::save_memory_layout (const wxChar* filename)
1430 {
1431     FILE * stream;
1432     list <mem_region>::iterator region;
1433
1434     // open the save file for writing
1435
1436     stream = _tfopen (filename, _T("wt"));
1437     if (stream == NULL)
1438         return false;
1439
1440     // write the save file format version number
1441
1442         fprintf (stream, "version %u\n", (unsigned int) MLT_FILE_VERSION);
1443
1444     // save the memory region data in address order
1445
1446     for (region = region_list.begin (); region != region_list.end (); ++region)
1447         fprintf (stream, "region %s %lx %lx %d %s\n", region->name.c_str (),
1448             region->address, region->size, (region->type == read_only), encode_note (region->note).c_str ());
1449
1450     // save the memory section data in VMA order
1451
1452     for (region = region_list.begin (); region != region_list.end(); ++region)
1453     {
1454         for (list <mem_section_view>::iterator section_view = region->section_view_list.begin (); section_view != region->section_view_list.end (); ++section_view)
1455         {
1456             if ((section_view->section != NULL) && (section_view->section_location != initial_location))
1457             {
1458                 list <mem_section>::iterator section = section_view->section;
1459                 fprintf (stream, "section %s %lx %lx %d %d %d %d %d %d",
1460                     section->name.c_str (), section->size, section->alignment,
1461                     section->relocates, section->linker_defined,
1462                     section->final_location->anchor == absolute,
1463                     section->final_location->following_section != NULL,
1464                     section->initial_location->anchor == absolute,
1465                     section->initial_location->following_section != NULL);
1466
1467                 if (section->final_location->anchor == absolute)
1468                     fprintf (stream, " %lx", section->final_location->address);
1469
1470                 if (section->initial_location->anchor == absolute)
1471                     fprintf (stream, " %lx", section->initial_location->address);
1472
1473                 if (section->final_location->following_section != NULL)
1474                     fprintf (stream, " %s", section->final_location->following_section->name.c_str ());
1475
1476                 if (section->initial_location->following_section != NULL)
1477                     fprintf (stream, " %s", section->initial_location->following_section->name.c_str ());
1478
1479                 fprintf (stream, " %s", encode_note (section->note).c_str ());
1480
1481                 // end of section description
1482
1483                 fprintf (stream, "\n"); // new line
1484             }
1485         }
1486     }
1487
1488     // close the file
1489
1490     if (fclose (stream))
1491         return false;
1492
1493         map_modified_flag = false;
1494     return true;
1495 }
1496
1497
1498 ////////////////////////////////////////////////////////////////////////
1499 // load_memory_layout() loads a previously saved memory layout from file
1500
1501 bool mem_map::load_memory_layout (const wxChar* filename)
1502 {
1503     FILE * stream;
1504
1505     // open the save file for reading
1506
1507     stream = _tfopen (filename, _T("rt"));
1508     if (stream == NULL)
1509         return false;
1510
1511         // read the file version
1512
1513         unsigned int file_version;
1514         if ((fscanf (stream, "%*s %u", &file_version) != 1) ||
1515                 (file_version != MLT_FILE_VERSION))
1516         {
1517                 fclose (stream); // missing or incorrect file version
1518         return false;
1519         }
1520
1521     new_memory_layout ();
1522
1523     // read the new memory layout (first pass)
1524
1525     while (! feof (stream))
1526     {
1527         char record_type [32];
1528         if (fscanf (stream, "%31s", record_type) == EOF)
1529             break;
1530
1531         if (strcmp (record_type, "section") == 0) // a section record
1532         {
1533             if (! load_memory_section_1 (stream))
1534                 break;
1535         }
1536         else if (strcmp (record_type, "region") == 0) // a region record
1537         {
1538             mem_address address, size;
1539             bool read_only_region;
1540             char name [32];
1541             char note [1024];
1542
1543             fscanf (stream, "%s %lx %lx %d %1023[^\n]", name, &address, &size, &read_only_region, note);
1544
1545             if (create_memory_region (name, address, size, (read_only_region ? read_only : read_write), decode_note (note)))
1546                 break;
1547         }   
1548         else // an unknown record type
1549             break;
1550     }
1551
1552         // quit if the end of the file was not reached (due to an error)
1553
1554         if (! feof (stream))
1555         {
1556                 new_memory_layout ();
1557                 fclose (stream);
1558                 return false;
1559         }
1560
1561     // move the file pointer back to the beginning of the file
1562
1563     fseek (stream, 0, SEEK_SET);
1564
1565     while (! feof (stream)) // read the memory layout (second pass)
1566     {
1567         char record_type [32];
1568         if (fscanf (stream, "%31s", record_type) == EOF)
1569             break;
1570
1571         if ((strcmp (record_type, "section") == 0) && (! load_memory_section_2 (stream)))
1572             break;
1573     }
1574     
1575     // close the file
1576
1577     if (fclose (stream))
1578         {
1579                 new_memory_layout ();
1580         return false;
1581         }
1582
1583     // recalculate section view lists for all regions
1584
1585     calc_section_lists ();
1586
1587         map_modified_flag = false;
1588     return true;
1589 }
1590
1591
1592 ////////////////////////////////////////////////////////////////////////
1593 // load_memory_section_1() loads a previously saved memory section from
1594 // file (first pass)
1595
1596 bool mem_map::load_memory_section_1 (FILE * stream)
1597 {
1598     char section_name [32];
1599     int relocates, linker_defined;
1600     int final_absolute, initial_absolute, final_following, initial_following;
1601     mem_section new_section;
1602
1603     new_section.initial_location = new mem_location;
1604     new_section.initial_location->following_section = NULL;
1605     new_section.final_location = new mem_location;
1606     new_section.final_location->following_section = NULL;
1607       
1608     fscanf (stream,"%31s %lx %lx %d %d %d %d %d %d",
1609         section_name, &new_section.size, &new_section.alignment,
1610         &relocates, &linker_defined, &final_absolute, &final_following,
1611         &initial_absolute, &initial_following);
1612
1613     new_section.name = section_name;
1614     new_section.relocates = (relocates != 0);
1615     new_section.linker_defined = (linker_defined != 0);
1616
1617     new_section.final_location->anchor = (final_absolute ? absolute : relative);
1618     if (final_absolute) // final location is absolute
1619         fscanf (stream, "%lx", &new_section.final_location->address);
1620
1621     new_section.initial_location->anchor = (initial_absolute ? absolute : relative);
1622     if (initial_absolute) // initial location is absolute
1623         fscanf (stream, "%lx", &new_section.initial_location->address);
1624
1625     if (final_following)
1626         fscanf (stream, "%*s"); // skip the final following section field on first pass
1627
1628     if (initial_following)
1629         fscanf (stream, "%*s"); // skip the initial following section field on first pass
1630
1631     char note [1024];
1632     fscanf (stream, " %1023[^\n]", note);
1633     new_section.note = decode_note (note);
1634
1635     // add the new section to the section map
1636
1637     section_list.push_front (new_section);
1638
1639     return true;
1640 }
1641
1642
1643 ////////////////////////////////////////////////////////////////////////
1644 // load_memory_section_2() loads a previously saved memory section from
1645 // file (second pass)
1646
1647 bool mem_map::load_memory_section_2 (FILE * stream)
1648 {
1649     char section_name [32];
1650     char following_section_name [32];
1651     int final_absolute, initial_absolute, final_following, initial_following;
1652
1653     fscanf (stream,"%31s %*lx %*lx %*d %*d %d %d %d %d",
1654         section_name, &final_absolute, &final_following,
1655         &initial_absolute, &initial_following);
1656
1657     if (final_absolute) // final location is absolute
1658         fscanf (stream, "%*lx"); // skip the final location
1659
1660     if (initial_absolute) // initial location is absolute
1661         fscanf (stream, "%*lx"); // skip the initial location
1662
1663     if (initial_following || final_following) // the section is a parent
1664     {
1665         list <mem_section>::iterator section = find_memory_section (section_name);
1666
1667         if (final_following)
1668         {
1669             fscanf (stream, "%31s", following_section_name); // read the final following section name
1670             section->final_location->following_section =
1671                 find_memory_section (following_section_name);
1672         }
1673
1674         if (initial_following)
1675         {
1676             fscanf (stream, "%31s", following_section_name); // read the initial following section name
1677             section->initial_location->following_section =
1678                 find_memory_section (following_section_name);
1679         }
1680     }
1681
1682     fscanf (stream, "%*1023[^\n]"); // skip the note
1683
1684     return true;
1685 }
1686
1687
1688 ////////////////////////////////////////////////////////////////////////
1689 // new_memory_layout() clears the memory layout
1690
1691 bool mem_map::new_memory_layout ()
1692 {
1693     delete_all_memory_sections ();
1694 //    section_list.clear ();
1695     region_list.clear ();
1696
1697         map_modified_flag = false; // no need to save an empty memory layout
1698     return true;
1699 }
1700
1701
1702 ////////////////////////////////////////////////////////////////////////
1703 // section_exists() determines if the specified section is defined
1704
1705 bool mem_map::section_exists (std::string section_name)
1706 {
1707     return (find_memory_section (section_name) != NULL);
1708 }
1709
1710
1711 ////////////////////////////////////////////////////////////////////////
1712 // find_region_by_address() finds the region containing the specified
1713 // memory address
1714
1715 list <mem_region>::iterator mem_map::find_region_by_address (mem_address address)
1716 {
1717     for (list <mem_region>::iterator region = region_list.begin (); region !=region_list.end(); ++region)
1718         if ((address >= region->address) && (address < region->address + region->size))
1719             return region;
1720
1721     return NULL; // the specified address is not in a memory region
1722 }
1723
1724
1725 ////////////////////////////////////////////////////////////////////////
1726 // find_region_by_section() finds the region containing the specified
1727 // section
1728
1729 list <mem_region>::iterator mem_map::find_region_by_section (list <mem_section>::iterator section, section_location_type location_type)
1730 {
1731     for (list <mem_region>::iterator region = region_list.begin (); region !=region_list.end(); ++region)
1732         for (list <mem_section_view>::iterator section_view = region->section_view_list.begin (); section_view != region->section_view_list.end (); ++section_view)
1733             if ((section_view->section != NULL) && (section_view->section == section) &&
1734                 (section_view->section_location == (section_view->section->relocates ? location_type : fixed_location)))
1735                 return region;
1736
1737     return NULL; // the specified section location type was not found (you probably searched for the fixed_location of a relocating section)
1738 }