test_generation.py 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2021 Espressif Systems (Shanghai) CO LTD
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. import collections
  18. import fnmatch
  19. import os
  20. import sys
  21. import tempfile
  22. import unittest
  23. try:
  24. from generation import Generation, GenerationException
  25. except ImportError:
  26. sys.path.append('../')
  27. from generation import Generation, GenerationException
  28. from io import StringIO
  29. from entity import Entity, EntityDB
  30. from fragments import FragmentFile
  31. from linker_script import LinkerScript
  32. from output_commands import AlignAtAddress, InputSectionDesc, SymbolAtAddress
  33. from sdkconfig import SDKConfig
  34. ROOT = Entity('*')
  35. FREERTOS = Entity('libfreertos.a')
  36. CROUTINE = Entity('libfreertos.a', 'croutine')
  37. TIMERS = Entity('libfreertos.a', 'timers')
  38. FREERTOS2 = Entity('libfreertos2.a')
  39. class GenerationTest(unittest.TestCase):
  40. def setUp(self):
  41. self.generation = Generation()
  42. self.entities = None
  43. self.linker_script = None
  44. with tempfile.NamedTemporaryFile(delete=False) as f:
  45. self.kconfigs_source_file = os.path.join(tempfile.gettempdir(), f.name)
  46. self.addCleanup(os.remove, self.kconfigs_source_file)
  47. with tempfile.NamedTemporaryFile(delete=False) as f:
  48. self.kconfig_projbuilds_source_file = os.path.join(tempfile.gettempdir(), f.name)
  49. self.addCleanup(os.remove, self.kconfig_projbuilds_source_file)
  50. os.environ['COMPONENT_KCONFIGS_SOURCE_FILE'] = self.kconfigs_source_file
  51. os.environ['COMPONENT_KCONFIGS_PROJBUILD_SOURCE_FILE'] = self.kconfig_projbuilds_source_file
  52. os.environ['COMPONENT_KCONFIGS'] = ''
  53. os.environ['COMPONENT_KCONFIGS_PROJBUILD'] = ''
  54. # prepare_kconfig_files.py doesn't have to be called because COMPONENT_KCONFIGS and
  55. # COMPONENT_KCONFIGS_PROJBUILD are empty
  56. self.sdkconfig = SDKConfig('data/Kconfig', 'data/sdkconfig')
  57. with open('data/base.lf') as fragment_file_obj:
  58. fragment_file = FragmentFile(fragment_file_obj, self.sdkconfig)
  59. self.generation.add_fragments_from_file(fragment_file)
  60. self.entities = EntityDB()
  61. with open('data/libfreertos.a.txt') as objdump:
  62. self.entities.add_sections_info(objdump)
  63. with open('data/linker_script.ld') as linker_script:
  64. self.linker_script = LinkerScript(linker_script)
  65. @staticmethod
  66. def create_fragment_file(contents, name='test_fragment.lf'):
  67. f = StringIO(contents)
  68. f.name = name
  69. return f
  70. def add_fragments(self, text):
  71. fragment_file = self.create_fragment_file(text)
  72. fragment_file = FragmentFile(fragment_file, self.sdkconfig)
  73. self.generation.add_fragments_from_file(fragment_file)
  74. def write(self, expected, actual):
  75. self.linker_script.fill(expected)
  76. self.linker_script.write(open('expected.ld', 'w'))
  77. self.linker_script.fill(actual)
  78. self.linker_script.write(open('actual.ld', 'w'))
  79. def generate_default_rules(self):
  80. rules = collections.defaultdict(list)
  81. rules['flash_text'].append(InputSectionDesc(ROOT, ['.literal', '.literal.*', '.text', '.text.*'], []))
  82. rules['flash_rodata'].append(InputSectionDesc(ROOT, ['.rodata', '.rodata.*'], []))
  83. rules['dram0_data'].append(InputSectionDesc(ROOT, ['.data', '.data.*'], []))
  84. rules['dram0_data'].append(InputSectionDesc(ROOT, ['.dram', '.dram.*'], []))
  85. rules['dram0_bss'].append(InputSectionDesc(ROOT, ['.bss', '.bss.*'], []))
  86. rules['dram0_bss'].append(InputSectionDesc(ROOT, ['COMMON'], []))
  87. rules['iram0_text'].append(InputSectionDesc(ROOT, ['.iram', '.iram.*'], []))
  88. rules['rtc_text'].append(InputSectionDesc(ROOT, ['.rtc.text', '.rtc.literal'], []))
  89. rules['rtc_data'].append(InputSectionDesc(ROOT, ['.rtc.data'], []))
  90. rules['rtc_data'].append(InputSectionDesc(ROOT, ['.rtc.rodata'], []))
  91. rules['rtc_bss'].append(InputSectionDesc(ROOT, ['.rtc.bss'], []))
  92. return rules
  93. def compare_rules(self, expected, actual):
  94. self.assertEqual(set(expected.keys()), set(actual.keys()))
  95. for target in sorted(actual.keys()):
  96. message = 'failed target %s' % target
  97. a_cmds = actual[target]
  98. e_cmds = expected[target]
  99. self.assertEqual(len(a_cmds), len(e_cmds), message)
  100. for a, e in zip(a_cmds, e_cmds):
  101. self.assertEqual(a, e, message)
  102. def get_default(self, target, rules):
  103. return rules[target][0]
  104. class DefaultMappingTest(GenerationTest):
  105. def test_rule_generation_default(self):
  106. # Checks that default rules are generated from
  107. # the default scheme properly and even if no mappings
  108. # are defined.
  109. actual = self.generation.generate(self.entities)
  110. expected = self.generate_default_rules()
  111. self.compare_rules(expected, actual)
  112. def test_default_mapping_lib(self):
  113. # Mapping a library with default mapping. This should not emit additional rules,
  114. # other than the default ones.
  115. mapping = u"""
  116. [mapping:test]
  117. archive: libfreertos.a
  118. entries:
  119. * (default)
  120. """
  121. self.add_fragments(mapping)
  122. self.test_rule_generation_default()
  123. def test_default_mapping_obj(self):
  124. # Mapping an object with default mapping. This should not emit additional rules,
  125. # other than the default ones.
  126. mapping = u"""
  127. [mapping:test]
  128. archive: libfreertos.a
  129. entries:
  130. croutine (default)
  131. """
  132. self.add_fragments(mapping)
  133. self.test_rule_generation_default()
  134. def test_default_mapping_symbol(self):
  135. # Mapping a symbol with default mapping. This should not emit additional rules,
  136. # other than the default ones.
  137. mapping = u"""
  138. [mapping:test]
  139. archive: libfreertos.a
  140. entries:
  141. croutine:prvCheckPendingReadyList (default) #1
  142. """
  143. self.add_fragments(mapping)
  144. self.test_rule_generation_default()
  145. def test_default_mapping_all(self):
  146. # Mapping a library, object, and symbol with default mapping. This should not emit additional rules,
  147. # other than the default ones.
  148. mapping = u"""
  149. [mapping:test]
  150. archive: libfreertos.a
  151. entries:
  152. * (default) #1
  153. croutine (default) #2
  154. croutine:prvCheckPendingReadyList (default) #3
  155. """
  156. self.add_fragments(mapping)
  157. self.test_rule_generation_default()
  158. def test_default_mapping_lib_symbol(self):
  159. # Mapping a library, and symbol with default mapping. This should not emit additional rules,
  160. # other than the default ones.
  161. #
  162. # This is a check needed to make sure generation does not generate
  163. # intermediate commands due to presence of symbol mapping.
  164. mapping = u"""
  165. [mapping:test]
  166. archive: libfreertos.a
  167. entries:
  168. * (default) #1
  169. croutine:prvCheckPendingReadyList (default) #2
  170. """
  171. self.add_fragments(mapping)
  172. self.test_rule_generation_default()
  173. def test_default_mapping_obj_symbol(self):
  174. # Mapping a library, and symbol with default mapping. This should not emit additional rules,
  175. # other than the default ones.
  176. #
  177. # This is a check needed to make sure generation does not generate
  178. # intermediate commands due to presence of symbol mapping.
  179. mapping = u"""
  180. [mapping:test]
  181. archive: libfreertos.a
  182. entries:
  183. croutine (default) #1
  184. croutine:prvCheckPendingReadyList (default) #2
  185. """
  186. self.add_fragments(mapping)
  187. self.test_rule_generation_default()
  188. class BasicTest(GenerationTest):
  189. # Test basic and fundamental interactions between typical
  190. # entries.
  191. def test_nondefault_mapping_lib(self, alt=None):
  192. # Test mapping entry different from default for a library.
  193. # There should be exclusions in the default commands for flash_text and flash_rodata:
  194. #
  195. # flash_text
  196. # *((EXCLUDE_FILE(libfreertos.a)) .literal ...) A
  197. #
  198. # Commands placing the entire library in iram, dram should be generated:
  199. #
  200. # iram0_text
  201. # *(.iram ...)
  202. # *libfreertos.a(.literal ...) B
  203. mapping = u"""
  204. [mapping:test]
  205. archive: libfreertos.a
  206. entries:
  207. * (noflash) #1
  208. """
  209. self.add_fragments(alt if alt else mapping)
  210. actual = self.generation.generate(self.entities)
  211. expected = self.generate_default_rules()
  212. flash_text = expected['flash_text']
  213. flash_rodata = expected['flash_rodata']
  214. iram0_text = expected['iram0_text']
  215. dram0_data = expected['dram0_data']
  216. # Generate exclusions in flash_text and flash_rodata A
  217. flash_text[0].exclusions.add(FREERTOS)
  218. flash_rodata[0].exclusions.add(FREERTOS)
  219. # Input section commands in iram_text and dram0_data for #1 B
  220. iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, []))
  221. dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, []))
  222. self.compare_rules(expected, actual)
  223. def test_nondefault_mapping_obj(self, alt=None):
  224. # Test mapping entry different from default for an object.
  225. # There should be exclusions in the default commands for flash_text and flash_rodata:
  226. #
  227. # flash_text
  228. # *((EXCLUDE_FILE(libfreertos.a:croutine)) .literal ...) A
  229. #
  230. # Commands placing the entire library in iram, dram should be generated:
  231. #
  232. # iram0_text
  233. # *(.iram ...)
  234. # *libfreertos.a:croutine(.literal ...) B
  235. mapping = u"""
  236. [mapping:test]
  237. archive: libfreertos.a
  238. entries:
  239. croutine (noflash) #1
  240. """
  241. self.add_fragments(alt if alt else mapping)
  242. actual = self.generation.generate(self.entities)
  243. expected = self.generate_default_rules()
  244. flash_text = expected['flash_text']
  245. flash_rodata = expected['flash_rodata']
  246. iram0_text = expected['iram0_text']
  247. dram0_data = expected['dram0_data']
  248. # Generate exclusions in flash_text and flash_rodata A
  249. flash_text[0].exclusions.add(CROUTINE)
  250. flash_rodata[0].exclusions.add(CROUTINE)
  251. # Input section commands in iram_text and dram0_data for #1 B
  252. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  253. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  254. self.compare_rules(expected, actual)
  255. def test_nondefault_mapping_symbol(self):
  256. # Test mapping entry different from default for symbol.
  257. # There should be exclusions in the default commands for flash_text, as well as the implicit intermediate object command
  258. # with an exclusion from default:
  259. #
  260. # flash_text
  261. # *((EXCLUDE_FILE(libfreertos.a:croutine)) .literal ...) A
  262. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) B
  263. #
  264. # Commands placing the entire library in iram should be generated:
  265. #
  266. # iram0_text
  267. # *(.iram ...)
  268. # *libfreertos.a:croutine(.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) C
  269. mapping = u"""
  270. [mapping:test]
  271. archive: libfreertos.a
  272. entries:
  273. croutine:prvCheckPendingReadyList (noflash) #1
  274. """
  275. self.add_fragments(mapping)
  276. actual = self.generation.generate(self.entities)
  277. expected = self.generate_default_rules()
  278. flash_text = expected['flash_text']
  279. iram0_text = expected['iram0_text']
  280. # Generate exclusion in flash_text A
  281. flash_text[0].exclusions.add(CROUTINE)
  282. # Generate intermediate command B
  283. # List all relevant sections except the symbol
  284. # being mapped
  285. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  286. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  287. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  288. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  289. filtered_sections.append('.text')
  290. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  291. # Input section commands in iram_text for #1 C
  292. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  293. self.compare_rules(expected, actual)
  294. def test_default_symbol_nondefault_lib(self):
  295. # Test default symbol mapping with different lib mapping. This should create an implicit intermediate object command.
  296. # The significant targets are flash_text, flash_rodata, iram0_text, dram0_data.
  297. #
  298. # flash_text
  299. # *(EXCLUDE_FILE(libfreertos.a) .text ...) A
  300. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) B
  301. #
  302. # flash_rodata
  303. # *(EXCLUDE_FILE(libfreertos.a) .rodata ...) A
  304. #
  305. # iram0_text
  306. # * ( .iram ...)
  307. # libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .text ...) C.1
  308. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) D
  309. #
  310. # dram0_data
  311. # * ( .dram ...)
  312. # libfreertos.a ( .rodata ...) C.2
  313. #
  314. # Only default commands are in the other targets.
  315. mapping = u"""
  316. [mapping:test]
  317. archive: libfreertos.a
  318. entries:
  319. * (noflash) #1
  320. croutine:prvCheckPendingReadyList (default) #2
  321. """
  322. self.add_fragments(mapping)
  323. actual = self.generation.generate(self.entities)
  324. expected = self.generate_default_rules()
  325. flash_text = expected['flash_text']
  326. flash_rodata = expected['flash_rodata']
  327. iram0_text = expected['iram0_text']
  328. dram0_data = expected['dram0_data']
  329. # Exclusions for #1 A
  330. flash_text[0].exclusions.add(FREERTOS)
  331. flash_rodata[0].exclusions.add(FREERTOS)
  332. # Commands for #1 C.1 & C.2
  333. # C.1 excludes intermediate command for #2
  334. iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE]))
  335. dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, []))
  336. # Intermediate command for excluding #2 D
  337. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  338. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  339. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  340. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  341. filtered_sections.append('.text')
  342. iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  343. # Command for #2 B
  344. flash_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  345. self.compare_rules(expected, actual)
  346. def test_default_symbol_nondefault_obj(self):
  347. # Test default symbol mapping with different obj mapping. Since there is an explicit entry for the object,
  348. # the sections for that object should just be expanded and the symbol section subtracted, to be placed
  349. # using another command.
  350. #
  351. # flash_text
  352. # *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  353. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) B
  354. #
  355. # flash_rodata
  356. # *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...) A
  357. #
  358. # iram0_text
  359. # *( .iram ...)
  360. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) C.1
  361. #
  362. # dram0_data
  363. # *(.data ..)
  364. # *libfreertos.a:croutine(.rodata ....) C.2
  365. #
  366. # Only default commands are in the other targets
  367. mapping = u"""
  368. [mapping:test]
  369. archive: libfreertos.a
  370. entries:
  371. croutine (noflash) #1
  372. croutine:prvCheckPendingReadyList (default) #2
  373. """
  374. self.add_fragments(mapping)
  375. actual = self.generation.generate(self.entities)
  376. expected = self.generate_default_rules()
  377. flash_text = expected['flash_text']
  378. flash_rodata = expected['flash_rodata']
  379. iram0_text = expected['iram0_text']
  380. dram0_data = expected['dram0_data']
  381. # Exclusions for #1 A
  382. flash_text[0].exclusions.add(CROUTINE)
  383. flash_rodata[0].exclusions.add(CROUTINE)
  384. # Commands for #1 C.1 & C.2
  385. # C.1 list relevant sections for libfreertos.a:croutine to
  386. # exclude symbol to map
  387. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  388. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  389. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  390. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  391. filtered_sections.append('.text')
  392. iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  393. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  394. # Command for #2 B
  395. flash_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  396. self.compare_rules(expected, actual)
  397. def test_default_nondefault_alternating(self):
  398. # Here, each of the entries map sections to something different
  399. # than its one-level-up entry.
  400. #
  401. # * text -> flash, rodata -> flash
  402. # libfreertos.a text -> iram, rodata -> dram
  403. # libfreertos.a:croutine text -> flash, rodata -> flash
  404. # croutine:prvCheckPendingReadyList text -> iram
  405. #
  406. # The significant targets are flash_text, flash_rodata, iram0_text, and dram0_data.
  407. #
  408. # flash_text
  409. # *(EXCLUDE_FILE(libfreertos.a) .text ...) A
  410. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) B.1
  411. #
  412. # flash_rodata
  413. # *(EXCLUDE_FILE(libfreertos.a) .rodata ...) A
  414. # *libfreertos.a:croutine(.rodata .rodata.*) B.2
  415. #
  416. # iram0_text
  417. # * ( .iram ...)
  418. # libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .text ...) C
  419. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) D
  420. #
  421. # dram0_data
  422. # * ( .dram ...)
  423. # libfreertos.a (EXCLUDE_FILE(libfreertos:croutine) .rodata ...) C
  424. #
  425. # For the other targets only the default commands should be present.
  426. mapping = u"""
  427. [mapping:test]
  428. archive: libfreertos.a
  429. entries:
  430. * (noflash) #1
  431. croutine (default) #2
  432. croutine:prvCheckPendingReadyList (noflash) #3
  433. """
  434. self.add_fragments(mapping)
  435. actual = self.generation.generate(self.entities)
  436. expected = self.generate_default_rules()
  437. flash_text = expected['flash_text']
  438. flash_rodata = expected['flash_rodata']
  439. iram0_text = expected['iram0_text']
  440. dram0_data = expected['dram0_data']
  441. # Exclusions for #1 A
  442. # Only for flash_text and flash_rodata
  443. flash_text[0].exclusions.add(FREERTOS)
  444. flash_rodata[0].exclusions.add(FREERTOS)
  445. # Commands for #1 C
  446. # with exclusions for #2
  447. iram0_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE]))
  448. dram0_data.append(InputSectionDesc(FREERTOS, flash_rodata[0].sections, [CROUTINE]))
  449. # Commands for #2 B.1
  450. flash_rodata.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  451. # List all relevant sections in case of flash_text B.2
  452. # as exclusion for #3
  453. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  454. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  455. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  456. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  457. filtered_sections.append('.text')
  458. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  459. # Command for #3 D
  460. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  461. self.compare_rules(expected, actual)
  462. def test_nondefault_but_same_lib_and_obj(self):
  463. # Extension of DefaultMappingTest. Commands should not be generated for #2, since it does similar mapping
  464. # to #1. Output is similar to test_different_mapping_lib.
  465. mapping = u"""
  466. [mapping:test]
  467. archive: libfreertos.a
  468. entries:
  469. * (noflash) #1
  470. croutine (noflash) #2
  471. """
  472. self.test_nondefault_mapping_lib(mapping)
  473. def test_nondefault_but_same_lib_and_sym(self):
  474. # Extension of DefaultMappingTest. Commands should not be generated for #2, since it does similar mapping
  475. # to #1. Output is similar to test_different_mapping_lib.
  476. mapping = u"""
  477. [mapping:test]
  478. archive: libfreertos.a
  479. entries:
  480. * (noflash) #1
  481. croutine:prvCheckPendingReadyList (noflash) #2
  482. """
  483. self.test_nondefault_mapping_lib(mapping)
  484. def test_nondefault_but_same_obj_and_sym(self):
  485. # Commands should not be generated for #2, since it does similar mapping
  486. # to #1. Output is similar to test_different_mapping_obj.
  487. mapping = u"""
  488. [mapping:test]
  489. archive: libfreertos.a
  490. entries:
  491. croutine (noflash) #1
  492. croutine:prvCheckPendingReadyList (noflash) #2
  493. """
  494. self.test_nondefault_mapping_obj(mapping)
  495. def test_multiple_symbols_excluded_from_intermediate_command(self):
  496. # Test mapping multiple symbols from the same object.
  497. # All these symbols must be succesfully excluded from
  498. # the intermediate command.
  499. #
  500. # flash_text
  501. # * (EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  502. # libfreertos:croutine(.text ...) B
  503. #
  504. # iram0_text
  505. #
  506. #
  507. mapping = u"""
  508. [mapping:test]
  509. archive: libfreertos.a
  510. entries:
  511. croutine:prvCheckPendingReadyList (noflash) #1
  512. croutine:prvCheckDelayedList (noflash) #2
  513. """
  514. self.add_fragments(mapping)
  515. actual = self.generation.generate(self.entities)
  516. expected = self.generate_default_rules()
  517. flash_text = expected['flash_text']
  518. iram0_text = expected['iram0_text']
  519. # Exclusions for #1 & #2 intermediate command A
  520. flash_text[0].exclusions.add(CROUTINE)
  521. # Intermediate command for #1 & #2 which lists B
  522. # all relevant sections in croutine except prvCheckPendingReadyList
  523. # and prvCheckDelayedList
  524. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  525. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  526. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  527. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  528. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckDelayedList')]
  529. filtered_sections.append('.text')
  530. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  531. # Commands for #1 & 2
  532. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckDelayedList', '.literal.prvCheckDelayedList']), []))
  533. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  534. self.compare_rules(expected, actual)
  535. def test_root_mapping_fragment(self):
  536. # Test creation of a mapping fragment that maps '*'.
  537. # This should generate another default command in iram0_text:
  538. #
  539. # iram0_text
  540. # * (.custom_section) A
  541. # * (.iram .iram.*)
  542. mapping = u"""
  543. [sections:custom_section]
  544. entries:
  545. .custom_section
  546. [scheme:custom_scheme]
  547. entries:
  548. custom_section -> iram0_text
  549. [mapping:default2]
  550. archive: *
  551. entries:
  552. * (custom_scheme) #1
  553. """
  554. self.add_fragments(mapping)
  555. actual = self.generation.generate(self.entities)
  556. expected = self.generate_default_rules()
  557. # Generate default command A
  558. # Since these are the same 'specificity', the commands
  559. # are arranged alphabetically.
  560. expected['iram0_text'].append(expected['iram0_text'][0])
  561. expected['iram0_text'][0] = InputSectionDesc(ROOT, ['.custom_section'], [])
  562. self.compare_rules(expected, actual)
  563. class AdvancedTest(GenerationTest):
  564. # Test valid but quirky cases, corner cases, failure cases, and
  565. # cases involving interaction between schemes, other mapping
  566. # fragments.
  567. def test_same_entity_no_scheme_common(self):
  568. # Test same entity being mapped by schemes that have nothing in common.
  569. #
  570. # noflash_data: rodata -> dram0_data
  571. # noflash_text: text -> iram0_text
  572. #
  573. # This operation should succeed with the following commands:
  574. #
  575. # flash_text
  576. # *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  577. #
  578. # flash_rodata
  579. # *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...) B
  580. #
  581. # iram0_text
  582. # *(.iram ...)
  583. # *libfreertos.a:croutine(.text .text.* ...) C
  584. #
  585. # dram0_data
  586. # *(.data ..)
  587. # *(.dram ...)
  588. # *libfreertos.a:croutine(.rodata .rodata.*) D
  589. mapping = u"""
  590. [mapping:test]
  591. archive: libfreertos.a
  592. entries:
  593. croutine (noflash_text) #1
  594. croutine (noflash_data) #2
  595. """
  596. self.add_fragments(mapping)
  597. actual = self.generation.generate(self.entities)
  598. expected = self.generate_default_rules()
  599. flash_text = expected['flash_text']
  600. flash_rodata = expected['flash_rodata']
  601. iram0_text = expected['iram0_text']
  602. dram0_data = expected['dram0_data']
  603. # Exclusions for #1 A
  604. flash_text[0].exclusions.add(CROUTINE)
  605. # Exclusions for #2 B
  606. flash_rodata[0].exclusions.add(CROUTINE)
  607. # Command for #1 C
  608. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  609. # Command for #2 D
  610. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  611. self.compare_rules(expected, actual)
  612. def test_same_entity_sub_scheme(self):
  613. # Test same entity being mapped by scheme that is a subset of the other.
  614. #
  615. # noflash: text -> iram0_text, rodata -> dram0_data
  616. # noflash_text: text -> iram0_text
  617. #
  618. # `text -> iram0_text` is common between the two schemes.
  619. #
  620. # This operation should succeed with the following commands:
  621. #
  622. # flash_text
  623. # *(EXCLUDE_FILE(libfreertos.a:croutine) .text ...) A
  624. #
  625. # flash_rodata
  626. # *(EXCLUDE_FILE(libfreertos.a:croutine) .rodata ...) B
  627. #
  628. # iram0_text
  629. # *(.iram ...)
  630. # *libfreertos.a:croutine(.text .text.* ...) C
  631. #
  632. # dram0_data
  633. # *(.data ..)
  634. # *(.dram ...)
  635. # *libfreertos.a:croutine(.rodata .rodata.*) D
  636. mapping = u"""
  637. [mapping:test]
  638. archive: libfreertos.a
  639. entries:
  640. croutine (noflash) #1
  641. croutine (noflash_data) #2
  642. """
  643. self.add_fragments(mapping)
  644. actual = self.generation.generate(self.entities)
  645. expected = self.generate_default_rules()
  646. flash_text = expected['flash_text']
  647. flash_rodata = expected['flash_rodata']
  648. iram0_text = expected['iram0_text']
  649. dram0_data = expected['dram0_data']
  650. # Exclusions for #1 A
  651. flash_text[0].exclusions.add(CROUTINE)
  652. # Exclusions for #1 & #2 B
  653. flash_rodata[0].exclusions.add(CROUTINE)
  654. # Command for #1 C
  655. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  656. # Command for #1 & #2 D
  657. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  658. self.compare_rules(expected, actual)
  659. def test_same_entity_conflicting_scheme(self, alt=None):
  660. # Test same entity being mapped by scheme conflicting with another.
  661. #
  662. # rtc = text -> rtc_text, rodata -> rtc_data
  663. # noflash = text -> iram0_text, rodata -> dram0_data
  664. #
  665. # This operation should fail.
  666. mapping = u"""
  667. [mapping:test]
  668. archive: libfreertos.a
  669. entries:
  670. croutine (noflash) #1
  671. croutine (rtc) #2
  672. """
  673. self.add_fragments(alt if alt else mapping)
  674. with self.assertRaises(GenerationException):
  675. self.generation.generate(self.entities)
  676. def test_complex_mapping_case(self, alt=None):
  677. # Test a complex case where an object is mapped using
  678. # one scheme, but a specific symbol in that object is mapped
  679. # using another. Another object and symbol is mapped the other way around.
  680. #
  681. # flash_text
  682. # *(EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:timers) .text ...) A, B
  683. #
  684. # flash_rodata
  685. # *(EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:timers) .rodata ...) A, B
  686. #
  687. # dram0_data
  688. # *(EXCLUDE_FILES(libfreertos.a:timers) .data ..) B
  689. # *(.dram ...)
  690. # *libfreertos.a:croutine(.rodata .rodata.*) C
  691. # *libfreertos.a:timers(.rodata.prvProcessReceivedCommands ...) E
  692. #
  693. # dram0_bss
  694. # *(EXCLUDE_FILE(libfreertos.a:timers) .bss .bss.* ...) B
  695. # *(EXCLUDE_FILE(libfreertos.a:timers) COMMON) B
  696. #
  697. # iram0_text
  698. # *(.iram ...)
  699. # *libfreertos.a:croutine(.literal .literal.prvCheckDelayedList ...) C
  700. # *libfreertos.a:timers(.literal .literal.prvProcessReceivedCommands ...) E
  701. #
  702. # rtc_text
  703. # *(rtc.text .rtc.literal)
  704. # libfreertos.a:croutine (.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) F
  705. # libfreertos.a:timers (.text .text.prvCheckForValidListAndQueue ...) D.2
  706. #
  707. # rtc_data
  708. # *(rtc.data)
  709. # *(rtc.rodata)
  710. # libfreertos.a:timers (.data .data.*) D
  711. # libfreertos.a:timers (.rodata ...) D.2
  712. #
  713. # rtc_bss
  714. # *(rtc.bss .rtc.bss)
  715. # libfreertos.a:timers (.bss .bss.*) D
  716. # libfreertos.a:timers (COMMON) D
  717. mapping = u"""
  718. [mapping:test]
  719. archive: libfreertos.a
  720. entries:
  721. croutine (noflash) #1
  722. timers (rtc) #2
  723. timers:prvProcessReceivedCommands (noflash) #3
  724. croutine:prvCheckPendingReadyList (rtc) #4
  725. """
  726. self.add_fragments(alt if alt else mapping)
  727. actual = self.generation.generate(self.entities)
  728. expected = self.generate_default_rules()
  729. flash_text = expected['flash_text']
  730. flash_rodata = expected['flash_rodata']
  731. dram0_data = expected['dram0_data']
  732. iram0_text = expected['iram0_text']
  733. dram0_bss = expected['dram0_bss']
  734. rtc_text = expected['rtc_text']
  735. rtc_data = expected['rtc_data']
  736. rtc_bss = expected['rtc_bss']
  737. # Exclusions for #1 A
  738. flash_text[0].exclusions.add(CROUTINE)
  739. flash_rodata[0].exclusions.add(CROUTINE)
  740. # Exclusions for #2 B
  741. flash_text[0].exclusions.add(TIMERS)
  742. flash_rodata[0].exclusions.add(TIMERS)
  743. dram0_data[0].exclusions.add(TIMERS)
  744. dram0_bss[0].exclusions.add(TIMERS)
  745. dram0_bss[1].exclusions.add(TIMERS)
  746. # Commands for #1 C
  747. # List all relevant sections excluding #4 for text -> iram0_text
  748. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  749. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  750. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  751. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  752. filtered_sections.append('.text')
  753. iram0_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  754. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  755. # Commands for #4 F
  756. # Processed first due to alphabetical ordering
  757. rtc_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  758. # Commands for #2 D
  759. # List all relevant sections excluding #3 for text -> rtc_text and D.2
  760. # rodata -> rtc_data
  761. timers_sections = self.entities.get_sections('libfreertos.a', 'timers')
  762. filtered_sections = fnmatch.filter(timers_sections, '.literal.*')
  763. filtered_sections.extend(fnmatch.filter(timers_sections, '.text.*'))
  764. filtered_sections = [s for s in filtered_sections if not s.endswith('prvProcessReceivedCommands')]
  765. filtered_sections.append('.text')
  766. rtc_text.append(InputSectionDesc(TIMERS, set(filtered_sections), []))
  767. rtc_data.append(InputSectionDesc(TIMERS, dram0_data[0].sections, []))
  768. filtered_sections = fnmatch.filter(timers_sections, '.rodata.*')
  769. filtered_sections = [s for s in filtered_sections if not s.endswith('prvProcessReceivedCommands')]
  770. rtc_data.append(InputSectionDesc(TIMERS, set(filtered_sections), []))
  771. rtc_bss.append(InputSectionDesc(TIMERS, dram0_bss[0].sections, []))
  772. rtc_bss.append(InputSectionDesc(TIMERS, dram0_bss[1].sections, []))
  773. # Commands for #3 E
  774. iram0_text.append(InputSectionDesc(TIMERS, set(['.text.prvProcessReceivedCommands', '.literal.prvProcessReceivedCommands']), []))
  775. dram0_data.append(InputSectionDesc(TIMERS, set(['.rodata.prvProcessReceivedCommands']), []))
  776. self.compare_rules(expected, actual)
  777. def test_multiple_mapping_fragments(self):
  778. # Test mapping multiple fragments succeeds, particularly
  779. # generating exclusions from the default command of archive
  780. # and object specificity.
  781. #
  782. # flash_text
  783. # * (EXCLUDE_FILE(libfreertos.a libfreertos.a:croutine) .text ...)
  784. #
  785. # flash_rodata
  786. # * (EXCLUDE_FILE(libfreertos.a libfreertos.a:croutine) .text ...)
  787. #
  788. # iram0_text
  789. mapping = u"""
  790. [mapping:test_1]
  791. archive: libfreertos.a
  792. entries:
  793. croutine (noflash) #1
  794. [mapping:test_2]
  795. archive: libfreertos2.a
  796. entries:
  797. * (noflash) #2
  798. """
  799. self.add_fragments(mapping)
  800. actual = self.generation.generate(self.entities)
  801. expected = self.generate_default_rules()
  802. flash_text = expected['flash_text']
  803. flash_rodata = expected['flash_rodata']
  804. iram0_text = expected['iram0_text']
  805. dram0_data = expected['dram0_data']
  806. # Exclusions for #1 A
  807. flash_text[0].exclusions.add(CROUTINE)
  808. flash_rodata[0].exclusions.add(CROUTINE)
  809. # Exclusions for #1 & #2 B
  810. flash_text[0].exclusions.add(FREERTOS2)
  811. flash_rodata[0].exclusions.add(FREERTOS2)
  812. # Command for #1 C
  813. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  814. dram0_data.append(InputSectionDesc(CROUTINE, flash_rodata[0].sections, []))
  815. # Command for #1 & #2 D
  816. iram0_text.append(InputSectionDesc(FREERTOS2, flash_text[0].sections, []))
  817. dram0_data.append(InputSectionDesc(FREERTOS2, flash_rodata[0].sections, []))
  818. self.compare_rules(expected, actual)
  819. def test_mapping_same_lib_in_multiple_fragments_no_conflict(self):
  820. # Test mapping fragments operating on the same archive.
  821. # In these cases, the entries are taken together.
  822. #
  823. # Uses the same entries as C_05 but spreads them across
  824. # two fragments. The output should still be the same.
  825. mapping = u"""
  826. [mapping:test_1]
  827. archive: libfreertos.a
  828. entries:
  829. croutine (noflash) #1
  830. timers:prvProcessReceivedCommands (noflash) #3
  831. [mapping:test_2]
  832. archive: libfreertos.a
  833. entries:
  834. timers (rtc) #2
  835. croutine:prvCheckPendingReadyList (rtc) #4
  836. """
  837. self.test_complex_mapping_case(mapping)
  838. def test_mapping_same_lib_in_multiple_fragments_conflict(self):
  839. # Test mapping fragments operating on the same archive
  840. # with conflicting mappings.
  841. mapping = u"""
  842. [mapping:test_1]
  843. archive: libfreertos.a
  844. entries:
  845. croutine (noflash) #1
  846. [mapping:test_2]
  847. archive: libfreertos.a
  848. entries:
  849. croutine (rtc) #2
  850. """
  851. self.test_same_entity_conflicting_scheme(mapping)
  852. def test_command_order(self):
  853. # Test command order sorting: the commands should be sorted by specificity, then
  854. # alphabetically. This contributes to deterministic output given
  855. # the same input mapping entries.
  856. #
  857. # This ordering is also tested in other tests as a side-effect.
  858. #
  859. # flash_text
  860. # * (EXCLUDE_FILE(libfreertos.a:croutine libfreertos.a:croutine2)) A
  861. # libfreertos.a:croutine(.text ....) B
  862. #
  863. # iram0_text
  864. #
  865. # * (.iram .iram.*)
  866. # libfreertos:croutine(.text .literal ...) C
  867. # libfreertos:croutine(.text.prvCheckDelayedList .literal.prvCheckDelayedList) F
  868. # libfreertos:croutine(.text.prvCheckPendingReadyList .literal.prvCheckPendingReadyList) G
  869. # libfreertos2:croutine(.text .literal ...) D
  870. # libfreertos2:croutine2(.text .literal ...) E
  871. mapping = u"""
  872. [mapping:freertos2]
  873. archive: libfreertos2.a
  874. entries:
  875. croutine2 (noflash_text) #1
  876. croutine (noflash_text) #2
  877. [mapping:freertos]
  878. archive: libfreertos.a
  879. entries:
  880. croutine:prvCheckPendingReadyList (noflash_text) #3
  881. croutine:prvCheckDelayedList (noflash_text) #4
  882. """
  883. self.add_fragments(mapping)
  884. actual = self.generation.generate(self.entities)
  885. expected = self.generate_default_rules()
  886. flash_text = expected['flash_text']
  887. iram0_text = expected['iram0_text']
  888. # Exclusions for #1 A
  889. flash_text[0].exclusions.add(CROUTINE)
  890. flash_text[0].exclusions.add(Entity(FREERTOS2.archive, 'croutine2'))
  891. flash_text[0].exclusions.add(Entity(FREERTOS2.archive, 'croutine'))
  892. # Intermediate command for #3 and #4 B
  893. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  894. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  895. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  896. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  897. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckDelayedList')]
  898. filtered_sections.append('.text')
  899. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  900. # Command for
  901. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckDelayedList', '.literal.prvCheckDelayedList']), []))
  902. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  903. iram0_text.append(InputSectionDesc(Entity(FREERTOS2.archive, 'croutine'), flash_text[0].sections, []))
  904. iram0_text.append(InputSectionDesc(Entity(FREERTOS2.archive, 'croutine2'), flash_text[0].sections, []))
  905. self.compare_rules(expected, actual)
  906. def test_ambigious_obj(self):
  907. # Command generation for ambiguous entry should fail.
  908. mapping = u"""
  909. [mapping:test]
  910. archive: libfreertos.a
  911. entries:
  912. port:xPortGetTickRateHz (noflash) #1
  913. """
  914. self.add_fragments(mapping)
  915. with self.assertRaises(GenerationException):
  916. self.generation.generate(self.entities)
  917. def test_disambiguated_obj(self):
  918. # Test command generation for disambiguated entry. Should produce similar
  919. # results to test_nondefault_mapping_symbol.
  920. mapping = u"""
  921. [mapping:test]
  922. archive: libfreertos.a
  923. entries:
  924. port.c:xPortGetTickRateHz (noflash) #1
  925. """
  926. port = Entity('libfreertos.a', 'port.c')
  927. self.add_fragments(mapping)
  928. actual = self.generation.generate(self.entities)
  929. expected = self.generate_default_rules()
  930. flash_text = expected['flash_text']
  931. iram0_text = expected['iram0_text']
  932. # Generate exclusion in flash_text A
  933. flash_text[0].exclusions.add(port)
  934. # Generate intermediate command B
  935. # List all relevant sections except the symbol
  936. # being mapped
  937. port_sections = self.entities.get_sections('libfreertos.a', 'port.c')
  938. filtered_sections = fnmatch.filter(port_sections, '.literal.*')
  939. filtered_sections.extend(fnmatch.filter(port_sections, '.text.*'))
  940. filtered_sections = [s for s in filtered_sections if not s.endswith('xPortGetTickRateHz')]
  941. filtered_sections.append('.text')
  942. flash_text.append(InputSectionDesc(port, set(filtered_sections), []))
  943. # Input section commands in iram_text for #1 C
  944. iram0_text.append(InputSectionDesc(port, set(['.text.xPortGetTickRateHz', '.literal.xPortGetTickRateHz']), []))
  945. self.compare_rules(expected, actual)
  946. def test_root_mapping_fragment_conflict(self):
  947. # Test that root mapping fragments are also checked for
  948. # conflicts.
  949. #
  950. # 'custom_scheme' entries conflict the 'default' scheme
  951. # entries.
  952. mapping = u"""
  953. [scheme:custom_scheme]
  954. entries:
  955. flash_text -> iram0_text
  956. [mapping:default2]
  957. archive: *
  958. entries:
  959. * (custom_scheme)
  960. """
  961. self.add_fragments(mapping)
  962. with self.assertRaises(GenerationException):
  963. self.generation.generate(self.entities)
  964. def test_root_mapping_fragment_duplicate(self):
  965. # Same root mappings have no effect.
  966. #
  967. # custom_scheme has the 'iram -> iram0_text' in common with
  968. # default scheme
  969. mapping = u"""
  970. [sections:custom_section]
  971. entries:
  972. .custom_section
  973. [scheme:custom_scheme]
  974. entries:
  975. iram -> iram0_text
  976. custom_section -> iram0_text
  977. [mapping:default2]
  978. archive: *
  979. entries:
  980. * (custom_scheme)
  981. """
  982. self.add_fragments(mapping)
  983. actual = self.generation.generate(self.entities)
  984. expected = self.generate_default_rules()
  985. # Generate default command A
  986. # Since these are the same 'specificity', the commands
  987. # are arranged alphabetically.
  988. expected['iram0_text'].append(expected['iram0_text'][0])
  989. expected['iram0_text'][0] = InputSectionDesc(ROOT, ['.custom_section'], [])
  990. self.compare_rules(expected, actual)
  991. class ConfigTest(GenerationTest):
  992. # Test command generation with conditions
  993. def _test_conditional_on_scheme(self, perf, alt=None):
  994. # Test that proper commands are generated if using
  995. # schemes with conditional entries.
  996. scheme = u"""
  997. [sections:cond_text_data]
  998. entries:
  999. if PERFORMANCE_LEVEL >= 1:
  1000. .text+
  1001. .literal+
  1002. else:
  1003. .rodata+
  1004. [scheme:cond_noflash]
  1005. entries:
  1006. if PERFORMANCE_LEVEL >= 1:
  1007. cond_text_data -> iram0_text
  1008. else:
  1009. cond_text_data -> dram0_data
  1010. """
  1011. mapping = u"""
  1012. [mapping:test]
  1013. archive: lib.a
  1014. entries:
  1015. * (cond_noflash)
  1016. """
  1017. self.sdkconfig.config.syms['PERFORMANCE_LEVEL'].set_value(str(perf))
  1018. self.add_fragments(scheme)
  1019. self.add_fragments(alt if alt else mapping)
  1020. actual = self.generation.generate(self.entities)
  1021. expected = self.generate_default_rules()
  1022. if perf >= 1:
  1023. flash_text = expected['flash_text']
  1024. iram0_text = expected['iram0_text']
  1025. flash_text[0].exclusions.add(Entity('lib.a'))
  1026. iram0_text.append(InputSectionDesc(Entity('lib.a'), flash_text[0].sections, []))
  1027. else:
  1028. flash_rodata = expected['flash_rodata']
  1029. dram0_data = expected['dram0_data']
  1030. flash_rodata[0].exclusions.add(Entity('lib.a'))
  1031. dram0_data.append(InputSectionDesc(Entity('lib.a'), flash_rodata[0].sections, []))
  1032. self.compare_rules(expected, actual)
  1033. def test_conditional_on_scheme_00(self):
  1034. self._test_conditional_on_scheme(0)
  1035. def test_conditional_on_scheme_01(self):
  1036. self._test_conditional_on_scheme(1)
  1037. def test_conditional_mapping(self, alt=None):
  1038. # Test that proper commands are generated
  1039. # in conditional mapping entries.
  1040. mapping = u"""
  1041. [mapping:default]
  1042. archive: *
  1043. entries:
  1044. * (default)
  1045. [mapping:test]
  1046. archive: lib.a
  1047. entries:
  1048. if PERFORMANCE_LEVEL = 1:
  1049. obj1 (noflash)
  1050. elif PERFORMANCE_LEVEL = 2:
  1051. obj1 (noflash)
  1052. obj2 (noflash)
  1053. elif PERFORMANCE_LEVEL = 3:
  1054. obj1 (noflash)
  1055. obj2 (noflash)
  1056. obj3 (noflash)
  1057. """
  1058. for perf_level in range(0, 4):
  1059. self.sdkconfig.config.syms['PERFORMANCE_LEVEL'].set_value(str(perf_level))
  1060. self.generation.mappings = {}
  1061. self.add_fragments(alt if alt else mapping)
  1062. actual = self.generation.generate(self.entities)
  1063. expected = self.generate_default_rules()
  1064. if perf_level < 4 and perf_level > 0:
  1065. for append_no in range(1, perf_level + 1):
  1066. flash_text = expected['flash_text']
  1067. flash_rodata = expected['flash_rodata']
  1068. iram0_text = expected['iram0_text']
  1069. dram0_data = expected['dram0_data']
  1070. obj_str = 'obj' + str(append_no)
  1071. flash_text[0].exclusions.add(Entity('lib.a', obj_str))
  1072. flash_rodata[0].exclusions.add(Entity('lib.a', obj_str))
  1073. iram0_text.append(InputSectionDesc(Entity('lib.a', obj_str), flash_text[0].sections, []))
  1074. dram0_data.append(InputSectionDesc(Entity('lib.a', obj_str), flash_rodata[0].sections, []))
  1075. self.compare_rules(expected, actual)
  1076. def test_conditional_on_scheme_legacy_mapping_00(self):
  1077. # Test use of conditional scheme on legacy mapping fragment grammar.
  1078. mapping = u"""
  1079. [mapping]
  1080. archive: lib.a
  1081. entries:
  1082. * (cond_noflash)
  1083. """
  1084. self._test_conditional_on_scheme(0, mapping)
  1085. def test_conditional_on_scheme_legacy_mapping_01(self):
  1086. # Test use of conditional scheme on legacy mapping fragment grammar.
  1087. mapping = u"""
  1088. [mapping]
  1089. archive: lib.a
  1090. entries:
  1091. * (cond_noflash)
  1092. """
  1093. self._test_conditional_on_scheme(0, mapping)
  1094. def test_conditional_entries_legacy_mapping_fragment(self):
  1095. # Test conditional entries on legacy mapping fragment grammar.
  1096. mapping = u"""
  1097. [mapping:default]
  1098. archive: *
  1099. entries:
  1100. * (default)
  1101. [mapping]
  1102. archive: lib.a
  1103. entries:
  1104. : PERFORMANCE_LEVEL = 0
  1105. : PERFORMANCE_LEVEL = 1
  1106. obj1 (noflash)
  1107. : PERFORMANCE_LEVEL = 2
  1108. obj1 (noflash)
  1109. obj2 (noflash)
  1110. : PERFORMANCE_LEVEL = 3
  1111. obj1 (noflash)
  1112. obj2 (noflash)
  1113. obj3 (noflash)
  1114. """
  1115. self.test_conditional_mapping(mapping)
  1116. def test_multiple_fragment_same_lib_conditional_legacy(self):
  1117. # Test conditional entries on legacy mapping fragment grammar
  1118. # across multiple fragments.
  1119. mapping = u"""
  1120. [mapping:default]
  1121. archive: *
  1122. entries:
  1123. * (default)
  1124. [mapping]
  1125. archive: lib.a
  1126. entries:
  1127. : PERFORMANCE_LEVEL = 0
  1128. : PERFORMANCE_LEVEL = 1
  1129. obj1 (noflash)
  1130. : PERFORMANCE_LEVEL = 2
  1131. obj1 (noflash)
  1132. : PERFORMANCE_LEVEL = 3
  1133. obj1 (noflash)
  1134. [mapping]
  1135. archive: lib.a
  1136. entries:
  1137. : PERFORMANCE_LEVEL = 1
  1138. obj1 (noflash) # ignore duplicate definition
  1139. : PERFORMANCE_LEVEL = 2
  1140. obj2 (noflash)
  1141. : PERFORMANCE_LEVEL = 3
  1142. obj2 (noflash)
  1143. obj3 (noflash)
  1144. """
  1145. self.test_conditional_mapping(mapping)
  1146. def test_multiple_fragment_same_lib_conditional(self):
  1147. # Test conditional entries on new mapping fragment grammar.
  1148. # across multiple fragments.
  1149. mapping = u"""
  1150. [mapping:default]
  1151. archive: *
  1152. entries:
  1153. * (default)
  1154. [mapping:base]
  1155. archive: lib.a
  1156. entries:
  1157. if PERFORMANCE_LEVEL = 1:
  1158. obj1 (noflash)
  1159. elif PERFORMANCE_LEVEL = 2:
  1160. obj1 (noflash)
  1161. elif PERFORMANCE_LEVEL = 3:
  1162. obj1 (noflash)
  1163. [mapping:extra]
  1164. archive: lib.a
  1165. entries:
  1166. if PERFORMANCE_LEVEL = 1:
  1167. obj1 (noflash) # ignore duplicate definition
  1168. elif PERFORMANCE_LEVEL = 2:
  1169. obj2 (noflash)
  1170. elif PERFORMANCE_LEVEL = 3:
  1171. obj2 (noflash)
  1172. obj3 (noflash)
  1173. """
  1174. self.test_conditional_mapping(mapping)
  1175. class FlagTest(GenerationTest):
  1176. # Test correct generation of mapping fragment entries
  1177. # with flags.
  1178. def test_flags_basics(self):
  1179. # Test that input section commands additions are done (KEEP SORT).
  1180. # Test that order dependent commands are properly generated (ALIGN, SURROUND)
  1181. # Normally, if an entry has the same mapping as parent, commands.
  1182. # are not emitted for them. However, if there are flags, they should be -
  1183. # only for the scheme entries that have flags, though.
  1184. # Flag entries split across multiple entries work.
  1185. #
  1186. # flash_text
  1187. # *((EXCLUDE_FILE(libfreertos:timers libfreertos:croutine).text ...) A
  1188. # KEEP(* (SORT_BY_NAME(EXCLUDE_FILE(libfreertos:timers).text) ...) B
  1189. #
  1190. # flash_rodata
  1191. # *((EXCLUDE_FILE(libfreertos:timers) .rodata ...) C
  1192. # _sym2_start D.1
  1193. # . = ALIGN(4) E.1
  1194. # KEEP(* (EXCLUDE_FILE(libfreertos:timers) .rodata ...) F
  1195. # _sym2_end D.2
  1196. # . = ALIGN(4) E.2
  1197. #
  1198. # iram0_text
  1199. # *(.iram .iram.*)
  1200. # . = ALIGN(4) G.1
  1201. # _sym1_start H.1
  1202. # libfreertos.a:croutine(.text .literal ...) I
  1203. # . = ALIGN(4) G.2
  1204. # _sym1_end H.2
  1205. mapping = u"""
  1206. [mapping:test]
  1207. archive: libfreertos.a
  1208. entries:
  1209. croutine (noflash_text);
  1210. text->iram0_text ALIGN(4, pre, post) SURROUND(sym1) #1
  1211. timers (default);
  1212. text->flash_text KEEP() SORT(name) #2
  1213. timers (default);
  1214. rodata->flash_rodata SURROUND(sym2) ALIGN(4, pre, post) #3
  1215. """
  1216. self.add_fragments(mapping)
  1217. actual = self.generation.generate(self.entities)
  1218. expected = self.generate_default_rules()
  1219. flash_text = expected['flash_text']
  1220. iram0_text = expected['iram0_text']
  1221. flash_rodata = expected['flash_rodata']
  1222. # Exclusions in flash_text for timers and croutine A
  1223. flash_text[0].exclusions.add(CROUTINE)
  1224. flash_text[0].exclusions.add(TIMERS)
  1225. # Command for #3 B
  1226. flash_text.append(InputSectionDesc(TIMERS, flash_text[0].sections, [], keep=True, sort=('name', None)))
  1227. # Exclusions in flash_rodata for timers C
  1228. flash_rodata[0].exclusions.add(TIMERS)
  1229. # Commands for #3 D.1, E.1, F, D.2, E.2
  1230. flash_rodata.append(SymbolAtAddress('_sym2_start'))
  1231. flash_rodata.append(AlignAtAddress(4))
  1232. flash_rodata.append(InputSectionDesc(TIMERS, flash_rodata[0].sections, []))
  1233. flash_rodata.append(SymbolAtAddress('_sym2_end'))
  1234. flash_rodata.append(AlignAtAddress(4))
  1235. # Commands for # G.1, H.1, I, G.2, H.2
  1236. iram0_text.append(AlignAtAddress(4))
  1237. iram0_text.append(SymbolAtAddress('_sym1_start'))
  1238. iram0_text.append(InputSectionDesc(CROUTINE, flash_text[0].sections, []))
  1239. iram0_text.append(AlignAtAddress(4))
  1240. iram0_text.append(SymbolAtAddress('_sym1_end'))
  1241. self.compare_rules(expected, actual)
  1242. def test_flags_intermediate_exclusion_command_root(self):
  1243. # Test that intermediate exclusion commands from root-level commands
  1244. # are included in the flags.
  1245. #
  1246. # flash_text
  1247. # _sym1_start A.1
  1248. # KEEP(* (EXCLUDE_FILE(libfreertos:croutine).text ...) B
  1249. # KEEP(libfreertos.a:croutine(...))) C
  1250. # _sym1_end A.2
  1251. #
  1252. # iram0_text
  1253. # *(.iram .iram.*)
  1254. # libfreertos.a:croutine(.text.prvCheckPendingReadyList ...) D
  1255. mapping = u"""
  1256. [mapping:default]
  1257. archive: *
  1258. entries:
  1259. # 1
  1260. * (default);
  1261. text->flash_text SURROUND(sym1) KEEP() #2
  1262. [mapping:test]
  1263. archive: libfreertos.a
  1264. entries:
  1265. croutine:prvCheckPendingReadyList (noflash_text) #3
  1266. """
  1267. self.generation.mappings = {}
  1268. self.add_fragments(mapping)
  1269. actual = self.generation.generate(self.entities)
  1270. expected = self.generate_default_rules()
  1271. flash_text = expected['flash_text']
  1272. iram0_text = expected['iram0_text']
  1273. # Command for #2, pre A.1
  1274. flash_text.insert(0, SymbolAtAddress('_sym1_start'))
  1275. # Command for #1 with KEEP() B
  1276. # and exclusion for #3
  1277. flash_text[1].keep = True
  1278. flash_text[1].exclusions.add(CROUTINE)
  1279. # Implicit exclusion command for #3 C
  1280. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  1281. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  1282. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  1283. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  1284. filtered_sections.append('.text')
  1285. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), [], keep=True))
  1286. # Command for #2, post A.2
  1287. flash_text.append(SymbolAtAddress('_sym1_end'))
  1288. # Command for #3 D
  1289. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  1290. self.compare_rules(expected, actual)
  1291. def test_flags_intermediate_exclusion_command_lib(self):
  1292. # Test that intermediate exclusion commands from lib-level commands
  1293. # are included in the flags.
  1294. #
  1295. # flash_text
  1296. # *(EXCLUDE_FILE(libfreertos.a).text ...)
  1297. # _sym1_start A.1
  1298. # KEEP(libfreertos.a(EXCLUDE_FILE(libfreertos:croutine).text.* ...)) B
  1299. # KEEP(libfreertos.a:croutine(...))) C
  1300. # _sym1_end A.2
  1301. #
  1302. # iram0_text
  1303. # *(.iram .iram.*)
  1304. # libfreertos.a:croutine(.text.prvCheckPendingReadyList ...) D
  1305. mapping = u"""
  1306. [mapping:test]
  1307. archive: libfreertos.a
  1308. entries:
  1309. # 1
  1310. * (default);
  1311. text->flash_text SURROUND(sym1) KEEP() #2
  1312. croutine:prvCheckPendingReadyList (noflash_text) #3
  1313. """
  1314. self.add_fragments(mapping)
  1315. actual = self.generation.generate(self.entities)
  1316. expected = self.generate_default_rules()
  1317. flash_text = expected['flash_text']
  1318. iram0_text = expected['iram0_text']
  1319. # Command for #2, pre A.1
  1320. flash_text.append(SymbolAtAddress('_sym1_start'))
  1321. flash_text[0].exclusions.add(FREERTOS)
  1322. # Command for #1 with KEEP() B
  1323. # and exclusion for #3
  1324. flash_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE], keep=True))
  1325. # Implicit exclusion command for #3 C
  1326. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  1327. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  1328. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  1329. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  1330. filtered_sections.append('.text')
  1331. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), [], keep=True))
  1332. # Command for #2, post A.2
  1333. flash_text.append(SymbolAtAddress('_sym1_end'))
  1334. # Command for #3 C
  1335. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  1336. self.compare_rules(expected, actual)
  1337. def test_flags_intermediate_exclusion_command_obj(self):
  1338. # Test that intermediate exclusion commands from obj-level commands
  1339. # are included in the flags.
  1340. #
  1341. # flash_text
  1342. # *(EXCLUDE_FILE(libfreertos.a).text ...)
  1343. # _sym1_start A.1
  1344. # KEEP(libfreertos.a:croutine(...))) B
  1345. # _sym1_end A.2
  1346. #
  1347. # iram0_text
  1348. # *(.iram .iram.*)
  1349. # libfreertos.a:croutine(.text.prvCheckPendingReadyList ...) C
  1350. mapping = u"""
  1351. [mapping:test]
  1352. archive: libfreertos.a
  1353. entries:
  1354. # 1
  1355. croutine (default);
  1356. text->flash_text SURROUND(sym1) KEEP() #2
  1357. croutine:prvCheckPendingReadyList (noflash_text) #3
  1358. """
  1359. self.add_fragments(mapping)
  1360. actual = self.generation.generate(self.entities)
  1361. expected = self.generate_default_rules()
  1362. flash_text = expected['flash_text']
  1363. iram0_text = expected['iram0_text']
  1364. # Command for #2, pre A.1
  1365. flash_text.append(SymbolAtAddress('_sym1_start'))
  1366. flash_text[0].exclusions.add(CROUTINE)
  1367. # Implicit exclusion command for #3 B
  1368. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  1369. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  1370. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  1371. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  1372. filtered_sections.append('.text')
  1373. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), [], keep=True))
  1374. # Command for #2, post A.2
  1375. flash_text.append(SymbolAtAddress('_sym1_end'))
  1376. # Command for #3 C
  1377. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  1378. self.compare_rules(expected, actual)
  1379. def test_flags_separate_exclusion_command_if_explicit_root(self):
  1380. # Explicit commands are separated from the parent's flags.
  1381. #
  1382. # flash_text
  1383. # _sym1_start A.1
  1384. # KEEP(* (EXCLUDE_FILE(libfreertos:croutine).text ...) B
  1385. # _sym1_end A.2
  1386. # KEEP(libfreertos.a:croutine(...))) C
  1387. #
  1388. # iram0_text
  1389. # *(.iram .iram.*)
  1390. # libfreertos.a:croutine(.text.prvCheckPendingReadyList ...) D
  1391. mapping = u"""
  1392. [mapping:default]
  1393. archive: *
  1394. entries:
  1395. # 1
  1396. * (default);
  1397. text->flash_text SURROUND(sym1) KEEP() #2
  1398. [mapping:test]
  1399. archive: libfreertos.a
  1400. entries:
  1401. croutine (default) #3
  1402. croutine:prvCheckPendingReadyList (noflash_text) #4
  1403. """
  1404. self.generation.mappings = {}
  1405. self.add_fragments(mapping)
  1406. actual = self.generation.generate(self.entities)
  1407. expected = self.generate_default_rules()
  1408. flash_text = expected['flash_text']
  1409. iram0_text = expected['iram0_text']
  1410. # Command for #2, pre A.1
  1411. flash_text.insert(0, SymbolAtAddress('_sym1_start'))
  1412. # Command for #1 with KEEP() B
  1413. # and exclusion for #3
  1414. flash_text[1].keep = True
  1415. flash_text[1].exclusions.add(CROUTINE)
  1416. # Command for #2, post A.2
  1417. flash_text.append(SymbolAtAddress('_sym1_end'))
  1418. # Command for #3 C
  1419. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  1420. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  1421. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  1422. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  1423. filtered_sections.append('.text')
  1424. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  1425. # Command for #4 D
  1426. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  1427. self.compare_rules(expected, actual)
  1428. def test_flags_separate_exclusion_command_if_explicit_lib(self):
  1429. # Explicit commands are separated from the parent's flags.
  1430. #
  1431. # flash_text
  1432. # *(EXCLUDE_FILE(libfreertos.a).text ...)
  1433. # _sym1_start A.1
  1434. # KEEP(libfreertos.a(EXCLUDE_FILE(libfreertos:croutine).text.* ...)) B
  1435. # _sym1_end A.2
  1436. # KEEP(libfreertos.a:croutine(...))) C
  1437. #
  1438. # iram0_text
  1439. # *(.iram .iram.*)
  1440. # libfreertos.a:croutine(.text.prvCheckPendingReadyList ...) D
  1441. mapping = u"""
  1442. [mapping:test]
  1443. archive: libfreertos.a
  1444. entries:
  1445. # 1
  1446. * (default);
  1447. text->flash_text SURROUND(sym1) KEEP()
  1448. croutine (default) #2
  1449. croutine:prvCheckPendingReadyList (noflash_text) #3
  1450. """
  1451. self.add_fragments(mapping)
  1452. actual = self.generation.generate(self.entities)
  1453. expected = self.generate_default_rules()
  1454. flash_text = expected['flash_text']
  1455. iram0_text = expected['iram0_text']
  1456. # Command for #2, pre A.1
  1457. flash_text.append(SymbolAtAddress('_sym1_start'))
  1458. flash_text[0].exclusions.add(FREERTOS)
  1459. # Command for #1 with KEEP() B
  1460. # and exclusion for #3
  1461. flash_text.append(InputSectionDesc(FREERTOS, flash_text[0].sections, [CROUTINE], keep=True))
  1462. # Command for #2, post A.2
  1463. flash_text.append(SymbolAtAddress('_sym1_end'))
  1464. # Implicit exclusion command for #3 C
  1465. croutine_sections = self.entities.get_sections('libfreertos.a', 'croutine')
  1466. filtered_sections = fnmatch.filter(croutine_sections, '.literal.*')
  1467. filtered_sections.extend(fnmatch.filter(croutine_sections, '.text.*'))
  1468. filtered_sections = [s for s in filtered_sections if not s.endswith('prvCheckPendingReadyList')]
  1469. filtered_sections.append('.text')
  1470. flash_text.append(InputSectionDesc(CROUTINE, set(filtered_sections), []))
  1471. # Command for #3 C
  1472. iram0_text.append(InputSectionDesc(CROUTINE, set(['.text.prvCheckPendingReadyList', '.literal.prvCheckPendingReadyList']), []))
  1473. self.compare_rules(expected, actual)
  1474. def test_flag_additions(self):
  1475. # Test ability to add flags as long as no other mapping fragments
  1476. # does the same thing.
  1477. mapping = u"""
  1478. [mapping:default_add_flag]
  1479. archive: *
  1480. entries:
  1481. * (default);
  1482. text->flash_text KEEP()
  1483. """
  1484. self.add_fragments(mapping)
  1485. actual = self.generation.generate(self.entities)
  1486. expected = self.generate_default_rules()
  1487. flash_text = expected['flash_text']
  1488. flash_text[0].keep = True
  1489. self.compare_rules(expected, actual)
  1490. def test_flags_flag_additions_duplicate(self):
  1491. # Test same flags added to same entity - these
  1492. # are ignored.
  1493. mapping = u"""
  1494. [mapping:default_add_flag_1]
  1495. archive: *
  1496. entries:
  1497. * (default);
  1498. text->flash_text KEEP()
  1499. [mapping:default_add_flag_2]
  1500. archive: *
  1501. entries:
  1502. * (default);
  1503. text->flash_text KEEP()
  1504. """
  1505. self.add_fragments(mapping)
  1506. actual = self.generation.generate(self.entities)
  1507. expected = self.generate_default_rules()
  1508. flash_text = expected['flash_text']
  1509. flash_text[0].keep = True
  1510. self.compare_rules(expected, actual)
  1511. def test_flags_flag_additions_conflict(self):
  1512. # Test condition where multiple fragments specifies flags
  1513. # to same entity - should generate exception.
  1514. mapping = u"""
  1515. [mapping:default_add_flag_1]
  1516. archive: *
  1517. entries:
  1518. * (default);
  1519. text->flash_text ALIGN(2)
  1520. [mapping:default_add_flag_2]
  1521. archive: *
  1522. entries:
  1523. * (default);
  1524. text->flash_text SURROUND(sym1)
  1525. """
  1526. self.add_fragments(mapping)
  1527. with self.assertRaises(GenerationException):
  1528. self.generation.generate(self.entities)
  1529. if __name__ == '__main__':
  1530. unittest.main()