test_generation.py 72 KB

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