2 * File: StExecutableImage.cpp
4 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5 * See included license file for license details.
8 #include "StExecutableImage.h"
14 StExecutableImage::StExecutableImage(int inAlignment)
15 : m_alignment(inAlignment),
21 //! Makes a duplicate of each memory region.
22 StExecutableImage::StExecutableImage(const StExecutableImage & inOther)
23 : m_name(inOther.m_name),
24 m_alignment(inOther.m_alignment),
25 m_hasEntry(inOther.m_hasEntry),
26 m_entry(inOther.m_entry),
27 m_filters(inOther.m_filters)
29 const_iterator it = inOther.getRegionBegin();
30 for (; it != inOther.getRegionEnd(); ++it)
32 const MemoryRegion & region = *it;
34 MemoryRegion regionCopy(region);
35 if (region.m_type == FILL_REGION && region.m_data != NULL)
37 regionCopy.m_data = new uint8_t[region.m_length];
38 memcpy(regionCopy.m_data, region.m_data, region.m_length);
41 m_image.push_back(regionCopy);
45 //! Disposes of memory allocated for each region.
46 StExecutableImage::~StExecutableImage()
48 MemoryRegionList::iterator it;
49 for (it = m_image.begin(); it != m_image.end(); ++it)
59 //! A copy of \a inName is made, so the original may be disposed of by the caller
60 //! after this method returns.
61 void StExecutableImage::setName(const std::string & inName)
66 std::string StExecutableImage::getName() const
71 // The region is added with read and write flags set.
72 //! \exception std::runtime_error will be thrown if the new overlaps an
74 void StExecutableImage::addFillRegion(uint32_t inAddress, unsigned inLength)
77 region.m_type = FILL_REGION;
78 region.m_address = inAddress;
80 region.m_length = inLength;
81 region.m_flags = REGION_RW_FLAG;
83 insertOrMergeRegion(region);
86 //! A copy of \a inData is made before returning. The copy will be deleted when
87 //! the executable image is destructed. Currently, the text region is created with
88 //! read, write, and executable flags set.
89 //! \exception std::runtime_error will be thrown if the new overlaps an
91 //! \exception std::bad_alloc is thrown if memory for the copy of \a inData
92 //! cannot be allocated.
93 void StExecutableImage::addTextRegion(uint32_t inAddress, const uint8_t * inData, unsigned inLength)
96 region.m_type = TEXT_REGION;
97 region.m_address = inAddress;
98 region.m_flags = REGION_RW_FLAG | REGION_EXEC_FLAG;
101 region.m_data = new uint8_t[inLength];
102 region.m_length = inLength;
103 memcpy(region.m_data, inData, inLength);
105 insertOrMergeRegion(region);
108 //! \exception std::out_of_range is thrown if \a inIndex is out of range.
110 const StExecutableImage::MemoryRegion & StExecutableImage::getRegionAtIndex(unsigned inIndex) const
113 if (inIndex >= m_image.size())
114 throw std::out_of_range("inIndex");
116 // find region by index
117 MemoryRegionList::const_iterator it = m_image.begin();
119 for (; it != m_image.end(); ++it, ++i)
127 //! The list of address filters is kept sorted as filters are added.
129 void StExecutableImage::addAddressFilter(const AddressFilter & filter)
131 m_filters.push_back(filter);
136 void StExecutableImage::clearAddressFilters()
141 //! \exception StExecutableImage::address_filter_exception Raised when a filter
142 //! with the type #ADDR_FILTER_ERROR or #ADDR_FILTER_WARNING is matched.
144 //! \todo Build a list of all matching filters and then execute them at once.
145 //! For the warning and error filters, a single exception should be raised
146 //! that identifies all the overlapping errors. Currently the user will only
147 //! see the first (lowest address) overlap.
148 void StExecutableImage::applyAddressFilters()
151 // Iterate over filters.
152 AddressFilterList::const_iterator fit = m_filters.begin();
153 for (; fit != m_filters.end(); ++fit)
155 const AddressFilter & filter = *fit;
157 // Iterator over regions.
158 MemoryRegionList::iterator rit = m_image.begin();
159 for (; rit != m_image.end(); ++rit)
161 MemoryRegion & region = *rit;
163 if (filter.matchesMemoryRegion(region))
165 switch (filter.m_action)
167 case ADDR_FILTER_NONE:
171 case ADDR_FILTER_ERROR:
172 // throw error exception
173 throw address_filter_exception(true, m_name, filter);
176 case ADDR_FILTER_WARNING:
177 // throw warning exception
178 throw address_filter_exception(false, m_name, filter);
181 case ADDR_FILTER_CROP:
182 // Delete the offending portion of the region and restart
183 // the iteration loops.
184 cropRegionToFilter(region, filter);
193 //! There are several possible cases here:
194 //! - No overlap at all. Nothing is done.
196 //! - All of the memory region is matched by the \a filter. The region is
197 //! removed from #StExecutableImage::m_image and its data memory freed.
199 //! - The remaining portion of the region is one contiguous chunk. In this
200 //! case, \a region is simply modified.
202 //! - The region is split in the middle by the filter. The original \a region
203 //! is modified to match the first remaining chunk. And a new #StExecutableImage::MemoryRegion
204 //! instance is created to hold the other leftover piece.
205 void StExecutableImage::cropRegionToFilter(MemoryRegion & region, const AddressFilter & filter)
207 uint32_t firstByte = region.m_address; // first byte occupied by this region
208 uint32_t lastByte = region.endAddress(); // last used byte in this region
210 // compute new address range
211 uint32_t cropFrom = filter.m_fromAddress;
212 if (cropFrom < firstByte)
214 cropFrom = firstByte;
217 uint32_t cropTo = filter.m_toAddress;
218 if (cropTo > lastByte)
223 // is there actually a match?
224 if (cropFrom > filter.m_toAddress || cropTo < filter.m_fromAddress)
226 // nothing to do, so bail
230 printf("Deleting region 0x%08x-0x%08x\n", cropFrom, cropTo);
232 // handle if the entire region is to be deleted
233 if (cropFrom == firstByte && cropTo == lastByte)
235 delete [] region.m_data;
236 region.m_data = NULL;
237 m_image.remove(region);
240 // there is at least a little of the original region remaining
241 uint32_t newLength = cropTo - cropFrom + 1;
242 uint32_t leftoverLength = lastByte - cropTo;
243 uint8_t * oldData = region.m_data;
246 region.m_address = cropFrom;
247 region.m_length = newLength;
249 // crop data buffer for text regions
250 if (region.m_type == TEXT_REGION && oldData)
252 region.m_data = new uint8_t[newLength];
253 memcpy(region.m_data, &oldData[cropFrom - firstByte], newLength);
255 // dispose of old data
259 // create a new region for any part of the original region that was past
260 // the crop to address. this will happen if the filter range falls in the
261 // middle of the region.
264 MemoryRegion newRegion;
265 newRegion.m_type = region.m_type;
266 newRegion.m_flags = region.m_flags;
267 newRegion.m_address = cropTo + 1;
268 newRegion.m_length = leftoverLength;
270 if (region.m_type == TEXT_REGION && oldData)
272 newRegion.m_data = new uint8_t[leftoverLength];
273 memcpy(newRegion.m_data, &oldData[cropTo - firstByte + 1], leftoverLength);
276 insertOrMergeRegion(newRegion);
280 //! \exception std::runtime_error will be thrown if \a inRegion overlaps an
283 //! \todo Need to investigate if we can use the STL sort algorithm at all. Even
284 //! though we're doing merges too, we could sort first then examine the list
286 void StExecutableImage::insertOrMergeRegion(MemoryRegion & inRegion)
288 uint32_t newStart = inRegion.m_address;
289 uint32_t newEnd = newStart + inRegion.m_length;
291 MemoryRegionList::iterator it = m_image.begin();
292 MemoryRegionList::iterator sortedPosition = m_image.begin();
293 for (; it != m_image.end(); ++it)
295 MemoryRegion & region = *it;
296 uint32_t thisStart = region.m_address;
297 uint32_t thisEnd = thisStart + region.m_length;
299 // keep track of where to insert it to retain sort order
300 if (thisStart >= newEnd)
305 // region types and flags must match in order to merge
306 if (region.m_type == inRegion.m_type && region.m_flags == inRegion.m_flags)
308 if (newStart == thisEnd || newEnd == thisStart)
310 mergeRegions(region, inRegion);
313 else if ((newStart >= thisStart && newStart < thisEnd) || (newEnd >= thisStart && newEnd < thisEnd))
315 throw std::runtime_error("new region overlaps existing region");
320 // not merged, so just insert it in the sorted position
321 m_image.insert(it, inRegion);
324 //! Extends \a inNewRegion to include the data in \a inOldRegion. It is
325 //! assumed that the two regions are compatible. The new region may come either
326 //! before or after the old region in memory. Note that while the two regions
327 //! don't necessarily have to be touching, it's probably a good idea. That's
328 //! because any data between the regions will be set to 0.
330 //! For TEXT_REGION types, the two original regions will have their data deleted
331 //! during the merge. Thus, this method is not safe if any outside callers may
332 //! be accessing the region's data.
333 void StExecutableImage::mergeRegions(MemoryRegion & inOldRegion, MemoryRegion & inNewRegion)
335 bool isOldBefore = inOldRegion.m_address < inNewRegion.m_address;
336 uint32_t oldEnd = inOldRegion.m_address + inOldRegion.m_length;
337 uint32_t newEnd = inNewRegion.m_address + inNewRegion.m_length;
339 switch (inOldRegion.m_type)
343 // calculate new length
347 newLength = newEnd - inOldRegion.m_address;
351 newLength = oldEnd - inNewRegion.m_address;
355 uint8_t * newData = new uint8_t[newLength];
356 memset(newData, 0, newLength);
358 // copy data from the two regions into new block
361 memcpy(newData, inOldRegion.m_data, inOldRegion.m_length);
362 memcpy(&newData[newLength - inNewRegion.m_length], inNewRegion.m_data, inNewRegion.m_length);
366 memcpy(newData, inNewRegion.m_data, inNewRegion.m_length);
367 memcpy(&newData[newLength - inOldRegion.m_length], inOldRegion.m_data, inOldRegion.m_length);
369 inOldRegion.m_address = inNewRegion.m_address;
372 // replace old region's data
373 delete [] inOldRegion.m_data;
374 inOldRegion.m_data = newData;
375 inOldRegion.m_length = newLength;
377 // delete new region's data
378 delete [] inNewRegion.m_data;
379 inNewRegion.m_data = NULL;
387 inOldRegion.m_length = newEnd - inOldRegion.m_address;
391 inOldRegion.m_length = oldEnd - inNewRegion.m_address;
392 inOldRegion.m_address = inNewRegion.m_address;
399 //! Used when we remove a region from the region list by value. Because this
400 //! operator compares the #m_data member, it will only return true for either an
401 //! exact copy or a reference to the original.
402 bool StExecutableImage::MemoryRegion::operator == (const MemoryRegion & other)
404 return (m_type == other.m_type) && (m_address == other.m_address) && (m_length == other.m_length) && (m_flags == other.m_flags) && (m_data == other.m_data);
407 //! Returns true if the address filter overlaps \a region.
408 bool StExecutableImage::AddressFilter::matchesMemoryRegion(const MemoryRegion & region) const
410 uint32_t firstByte = region.m_address; // first byte occupied by this region
411 uint32_t lastByte = region.endAddress(); // last used byte in this region
412 return (firstByte >= m_fromAddress && firstByte <= m_toAddress) || (lastByte >= m_fromAddress && lastByte <= m_toAddress);
415 //! The comparison does \em not take the action into account. It only looks at the
416 //! priority and address ranges of each filter. Priority is considered only if the two
417 //! filters overlap. Lower priority filters will come after higher priority ones.
419 //! \retval -1 This filter is less than filter \a b.
420 //! \retval 0 This filter is equal to filter \a b.
421 //! \retval 1 This filter is greater than filter \a b.
422 int StExecutableImage::AddressFilter::compare(const AddressFilter & other) const
424 if (m_priority != other.m_priority && ((m_fromAddress >= other.m_fromAddress && m_fromAddress <= other.m_toAddress) || (m_toAddress >= other.m_fromAddress && m_toAddress <= other.m_toAddress)))
426 // we know the priorities are not equal
427 if (m_priority > other.m_priority)
437 if (m_fromAddress == other.m_fromAddress)
439 if (m_toAddress == other.m_toAddress)
443 else if (m_toAddress < other.m_toAddress)
452 else if (m_fromAddress < other.m_fromAddress)