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