From 0142676cbfa84cc35765959effa0ed34c4910331 Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Wed, 27 Jan 2021 16:02:44 +0800 Subject: [PATCH] ldgen: additional tests for generation support classes --- tools/ci/config/host-test.yml | 6 +- tools/ci/executable-list.txt | 2 + tools/ldgen/output_commands.py | 78 ++++++ tools/ldgen/test/data/{sample.lf => base.lf} | 0 .../data/{sections.info => libfreertos.a.txt} | 105 ++++++++ .../data/{template.ld => linker_script.ld} | 0 .../test/data/test_entity/libfreertos.a.txt | 39 +++ .../parse_test.txt} | 6 +- tools/ldgen/test/test_entity.py | 251 ++++++++++++++++++ tools/ldgen/test/test_output_commands.py | 141 ++++++++++ 10 files changed, 623 insertions(+), 5 deletions(-) create mode 100644 tools/ldgen/output_commands.py rename tools/ldgen/test/data/{sample.lf => base.lf} (100%) rename tools/ldgen/test/data/{sections.info => libfreertos.a.txt} (93%) rename tools/ldgen/test/data/{template.ld => linker_script.ld} (100%) create mode 100644 tools/ldgen/test/data/test_entity/libfreertos.a.txt rename tools/ldgen/test/data/{sections_parse.info => test_entity/parse_test.txt} (71%) create mode 100755 tools/ldgen/test/test_entity.py create mode 100755 tools/ldgen/test/test_output_commands.py diff --git a/tools/ci/config/host-test.yml b/tools/ci/config/host-test.yml index 645aeb306b..bd25368edf 100644 --- a/tools/ci/config/host-test.yml +++ b/tools/ci/config/host-test.yml @@ -72,8 +72,10 @@ test_ldgen_on_host: extends: .host_test_template script: - cd tools/ldgen/test - - ./test_fragments.py - - ./test_generation.py + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_fragments.py + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_generation.py + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_entity.py + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_output_commands.py variables: LC_ALL: C.UTF-8 diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 1ce46dea38..1c446afa3e 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -88,8 +88,10 @@ tools/kconfig_new/test/confserver/test_confserver.py tools/kconfig_new/test/gen_kconfig_doc/test_kconfig_out.py tools/kconfig_new/test/gen_kconfig_doc/test_target_visibility.py tools/ldgen/ldgen.py +tools/ldgen/test/test_entity.py tools/ldgen/test/test_fragments.py tools/ldgen/test/test_generation.py +tools/ldgen/test/test_output_commands.py tools/mass_mfg/mfg_gen.py tools/mkdfu.py tools/mkuf2.py diff --git a/tools/ldgen/output_commands.py b/tools/ldgen/output_commands.py new file mode 100644 index 0000000000..93722f8497 --- /dev/null +++ b/tools/ldgen/output_commands.py @@ -0,0 +1,78 @@ +# +# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from entity import Entity + + +class InputSectionDesc(): + + def __init__(self, entity, sections, exclusions=None): + assert(entity.specificity != Entity.Specificity.SYMBOL) + + self.entity = entity + self.sections = set(sections) + + self.exclusions = set() + + if exclusions: + assert(not [e for e in exclusions if e.specificity == Entity.Specificity.SYMBOL or + e.specificity == Entity.Specificity.NONE]) + self.exclusions = set(exclusions) + else: + self.exclusions = set() + + def __str__(self): + if self.sections: + exclusion_strings = [] + + for exc in sorted(self.exclusions): + if exc.specificity == Entity.Specificity.ARCHIVE: + exc_string = '*%s' % (exc.archive) + else: + exc_string = '*%s:%s.*' % (exc.archive, exc.obj) + + exclusion_strings.append(exc_string) + + section_strings = [] + + if exclusion_strings: + exclusion_string = 'EXCLUDE_FILE(%s)' % ' '.join(exclusion_strings) + + for section in sorted(self.sections): + section_strings.append('%s %s' % (exclusion_string, section)) + else: + for section in sorted(self.sections): + section_strings.append(section) + + sections_string = '(%s)' % ' '.join(section_strings) + else: + sections_string = '( )' + + command = None + + if self.entity.specificity == Entity.Specificity.NONE: + command = '*%s' % (sections_string) + elif self.entity.specificity == Entity.Specificity.ARCHIVE: + command = '*%s:%s' % (self.entity.archive, sections_string) + else: + command = '*%s:%s.*%s' % (self.entity.archive, self.entity.obj, sections_string) + + return command + + def __eq__(self, other): + return (self.entity == other.entity and + self.sections == other.sections and + self.exclusions == other.exclusions) diff --git a/tools/ldgen/test/data/sample.lf b/tools/ldgen/test/data/base.lf similarity index 100% rename from tools/ldgen/test/data/sample.lf rename to tools/ldgen/test/data/base.lf diff --git a/tools/ldgen/test/data/sections.info b/tools/ldgen/test/data/libfreertos.a.txt similarity index 93% rename from tools/ldgen/test/data/sections.info rename to tools/ldgen/test/data/libfreertos.a.txt index 75c699702d..9f7821da91 100644 --- a/tools/ldgen/test/data/sections.info +++ b/tools/ldgen/test/data/libfreertos.a.txt @@ -343,6 +343,111 @@ Idx Name Size VMA LMA File off Algn 49 .xt.prop 00000408 00000000 00000000 00002f3e 2**0 CONTENTS, RELOC, READONLY +port.cpp.obj: file format elf32-xtensa-le + +Sections: +Idx Name Size VMA LMA File off Algn + 0 .literal.pxPortInitialiseStack 00000018 00000000 00000000 00000034 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 1 .literal.xPortStartScheduler 00000014 00000000 00000000 0000004c 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 2 .literal.xPortSysTickHandler 00000008 00000000 00000000 00000060 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 3 .literal.vPortYieldOtherCore 00000004 00000000 00000000 00000068 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 4 .literal.vPortReleaseTaskMPUSettings 00000004 00000000 00000000 0000006c 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 5 .literal.xPortInIsrContext 00000008 00000000 00000000 00000070 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 6 .iram1.literal 00000004 00000000 00000000 00000078 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 7 .literal.vPortAssertIfInISR 00000018 00000000 00000000 0000007c 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 8 .literal.vPortCPUInitializeMutex 00000004 00000000 00000000 00000094 2**2 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 9 .literal.vPortCPUAcquireMutex 00000030 00000000 00000000 00000098 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 10 .literal.vPortCPUAcquireMutexTimeout 00000030 00000000 00000000 000000c8 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 11 .literal.vPortCPUReleaseMutex 00000028 00000000 00000000 000000f8 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 12 .literal.vPortSetStackWatchpoint 00000008 00000000 00000000 00000120 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 13 .text 00000000 00000000 00000000 00000128 2**0 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 14 .data 00000000 00000000 00000000 00000128 2**0 + CONTENTS, ALLOC, LOAD, DATA + 15 .bss 00000000 00000000 00000000 00000128 2**0 + ALLOC + 16 .text.pxPortInitialiseStack 00000086 00000000 00000000 00000128 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 17 .text.vPortEndScheduler 00000005 00000000 00000000 000001b0 2**2 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 18 .text.xPortStartScheduler 0000002e 00000000 00000000 000001b8 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 19 .text.xPortSysTickHandler 00000016 00000000 00000000 000001e8 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 20 .text.vPortYieldOtherCore 0000000e 00000000 00000000 00000200 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 21 .text.vPortStoreTaskMPUSettings 00000013 00000000 00000000 00000210 2**2 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 22 .text.vPortReleaseTaskMPUSettings 0000000e 00000000 00000000 00000224 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 23 .text.xPortInIsrContext 00000026 00000000 00000000 00000234 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 24 .iram1 0000001a 00000000 00000000 0000025c 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 25 .rodata.str1.4 0000013b 00000000 00000000 00000278 2**2 + CONTENTS, ALLOC, LOAD, READONLY, DATA + 26 .text.vPortAssertIfInISR 00000025 00000000 00000000 000003b4 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 27 .text.vPortCPUInitializeMutex 0000000e 00000000 00000000 000003dc 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 28 .text.vPortCPUAcquireMutex 00000088 00000000 00000000 000003ec 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 29 .text.vPortCPUAcquireMutexTimeout 000000ab 00000000 00000000 00000474 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 30 .text.vPortCPUReleaseMutex 00000061 00000000 00000000 00000520 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 31 .text.vPortSetStackWatchpoint 0000001a 00000000 00000000 00000584 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 32 .text.xPortGetTickRateHz 00000008 00000000 00000000 000005a0 2**2 + CONTENTS, ALLOC, LOAD, READONLY, CODE + 33 .rodata.__func__$5264 00000029 00000000 00000000 000005a8 2**2 + CONTENTS, ALLOC, LOAD, READONLY, DATA + 34 .rodata.__func__$5259 00000029 00000000 00000000 000005d4 2**2 + CONTENTS, ALLOC, LOAD, READONLY, DATA + 35 .rodata.__FUNCTION__$5243 00000013 00000000 00000000 00000600 2**2 + CONTENTS, ALLOC, LOAD, READONLY, DATA + 36 .bss.port_interruptNesting 00000008 00000000 00000000 00000614 2**2 + ALLOC + 37 .bss.port_xSchedulerRunning 00000008 00000000 00000000 00000614 2**2 + ALLOC + 38 .debug_frame 00000190 00000000 00000000 00000614 2**2 + CONTENTS, RELOC, READONLY, DEBUGGING + 39 .debug_info 00000e78 00000000 00000000 000007a4 2**0 + CONTENTS, RELOC, READONLY, DEBUGGING + 40 .debug_abbrev 00000404 00000000 00000000 0000161c 2**0 + CONTENTS, READONLY, DEBUGGING + 41 .debug_loc 000005f1 00000000 00000000 00001a20 2**0 + CONTENTS, RELOC, READONLY, DEBUGGING + 42 .debug_aranges 00000098 00000000 00000000 00002011 2**0 + CONTENTS, RELOC, READONLY, DEBUGGING + 43 .debug_ranges 000000a0 00000000 00000000 000020a9 2**0 + CONTENTS, RELOC, READONLY, DEBUGGING + 44 .debug_line 000005fb 00000000 00000000 00002149 2**0 + CONTENTS, RELOC, READONLY, DEBUGGING + 45 .debug_str 0000071f 00000000 00000000 00002744 2**0 + CONTENTS, READONLY, DEBUGGING + 46 .comment 0000003b 00000000 00000000 00002e63 2**0 + CONTENTS, READONLY + 47 .xtensa.info 00000038 00000000 00000000 00002e9e 2**0 + CONTENTS, READONLY + 48 .xt.lit 00000068 00000000 00000000 00002ed6 2**0 + CONTENTS, RELOC, READONLY + 49 .xt.prop 00000408 00000000 00000000 00002f3e 2**0 + CONTENTS, RELOC, READONLY + portasm.S.obj: file format elf32-xtensa-le Sections: diff --git a/tools/ldgen/test/data/template.ld b/tools/ldgen/test/data/linker_script.ld similarity index 100% rename from tools/ldgen/test/data/template.ld rename to tools/ldgen/test/data/linker_script.ld diff --git a/tools/ldgen/test/data/test_entity/libfreertos.a.txt b/tools/ldgen/test/data/test_entity/libfreertos.a.txt new file mode 100644 index 0000000000..bc107f53b9 --- /dev/null +++ b/tools/ldgen/test/data/test_entity/libfreertos.a.txt @@ -0,0 +1,39 @@ +In archive /home/user/build/esp-idf/freertos/libfreertos.a: + +croutine.c.obj: file format elf32-xtensa-le + +Sections: +Idx Name Size VMA LMA File off Algn + 0 .literal.prvCheckPendingReadyList 00000018 00000000 00000000 00000034 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 1 .literal.prvCheckDelayedList 0000002c 00000000 00000000 0000004c 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + +croutine.cpp.obj: file format elf32-xtensa-le + +Sections: +Idx Name Size VMA LMA File off Algn + 9 .text.prvCheckPendingReadyList 00000056 00000000 00000000 000000d8 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 10 .text.prvCheckDelayedList 000000ac 00000000 00000000 00000130 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + +croutine.S.obj: file format elf32-xtensa-le + +Sections: +Idx Name Size VMA LMA File off Algn + 26 .debug_frame 000000a0 00000000 00000000 00000394 2**2 + CONTENTS, RELOC, READONLY, DEBUGGING + 27 .debug_info 000006b8 00000000 00000000 00000434 2**0 + CONTENTS, RELOC, READONLY, DEBUGGING + 28 .debug_abbrev 00000233 00000000 00000000 00000aec 2**0 + CONTENTS, READONLY, DEBUGGING + +timers.o: file format elf32-xtensa-le + +Sections: +Idx Name Size VMA LMA File off Algn + 0 .literal.prvGetNextExpireTime 00000004 00000000 00000000 00000034 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE + 1 .literal.prvInsertTimerInActiveList 00000010 00000000 00000000 00000038 2**2 + CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE diff --git a/tools/ldgen/test/data/sections_parse.info b/tools/ldgen/test/data/test_entity/parse_test.txt similarity index 71% rename from tools/ldgen/test/data/sections_parse.info rename to tools/ldgen/test/data/test_entity/parse_test.txt index cd2f137e88..4357f02032 100644 --- a/tools/ldgen/test/data/sections_parse.info +++ b/tools/ldgen/test/data/test_entity/parse_test.txt @@ -1,4 +1,4 @@ -In archive /home/user/ãóç+ěščřžýáíé/build/esp-idf/freertos/libsections_parse.a: +In archive /home/user/ãóç+ěščřžýáíé/build/esp-idf/freertos/ěščřžýáíé.a: croutine.c.obj: file format elf32-littleriscv @@ -11,9 +11,9 @@ Idx Name Size VMA LMA File off Algn 2 .bss 00000000 00000000 00000000 00000034 2**0 ALLOC -FreeRTOS-openocd.c.obj: file format elf32-xtensa-le // 'F' should not get included in match for 'CONTENTS, ALLOC, LOAD ...' prior +FreeRTOS-ěščřžýáíé.c.obj: file format elf32-xtensa-le // 'F' should not get included in match for 'CONTENTS, ALLOC, LOAD ...' prior Sections: Idx Name Size VMA LMA File off Algn - 0 .literal.prvCheckPendingReadyList 00000018 00000000 00000000 00000034 2**2 + 0 .literal.ěščřžýáíé 00000018 00000000 00000000 00000034 2**2 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE diff --git a/tools/ldgen/test/test_entity.py b/tools/ldgen/test/test_entity.py new file mode 100755 index 0000000000..a7c2db157c --- /dev/null +++ b/tools/ldgen/test/test_entity.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python +# coding=utf-8 +# +# Copyright 2018-2020 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import sys +import unittest + +try: + from entity import Entity, EntityDB +except ImportError: + sys.path.append('../') + from entity import Entity, EntityDB + + +class EntityTest(unittest.TestCase): + + def test_create_none(self): + entity = Entity(Entity.ALL) + self.assertEqual(Entity.Specificity.NONE, entity.specificity) + + entity = Entity(None) + self.assertEqual(Entity.Specificity.NONE, entity.specificity) + + entity = Entity() + self.assertEqual(Entity.Specificity.NONE, entity.specificity) + + def test_create_archive(self): + entity = Entity('libfreertos.a') + self.assertEqual(Entity.Specificity.ARCHIVE, entity.specificity) + + entity = Entity('libfreertos.a', Entity.ALL, Entity.ALL) + self.assertEqual(Entity.Specificity.ARCHIVE, entity.specificity) + + entity = Entity('libfreertos.a', None, None) + self.assertEqual(Entity.Specificity.ARCHIVE, entity.specificity) + + entity = Entity('libfreertos.a', Entity.ALL, None) + self.assertEqual(Entity.Specificity.ARCHIVE, entity.specificity) + + entity = Entity('libfreertos.a', None, Entity.ALL) + self.assertEqual(Entity.Specificity.ARCHIVE, entity.specificity) + + def test_create_obj(self): + entity = Entity('libfreertos.a', 'croutine') + self.assertEqual(Entity.Specificity.OBJ, entity.specificity) + + entity = Entity('libfreertos.a', 'croutine', Entity.ALL) + self.assertEqual(Entity.Specificity.OBJ, entity.specificity) + + entity = Entity('libfreertos.a', 'croutine', None) + self.assertEqual(Entity.Specificity.OBJ, entity.specificity) + + def test_create_symbol(self): + entity = Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList') + self.assertEqual(Entity.Specificity.SYMBOL, entity.specificity) + + def test_create_invalid(self): + with self.assertRaises(ValueError): + Entity(None, 'croutine') + + with self.assertRaises(ValueError): + Entity(Entity.ALL, 'croutine') + + with self.assertRaises(ValueError): + Entity(None, None, 'prvCheckPendingReadyList') + + with self.assertRaises(ValueError): + Entity(Entity.ALL, Entity.ALL, 'prvCheckPendingReadyList') + + with self.assertRaises(ValueError): + Entity(None, Entity.ALL, 'prvCheckPendingReadyList') + + with self.assertRaises(ValueError): + Entity(Entity.ALL, None, 'prvCheckPendingReadyList') + + with self.assertRaises(ValueError): + Entity('libfreertos.a', None, 'prvCheckPendingReadyList') + + with self.assertRaises(ValueError): + Entity('libfreertos.a', Entity.ALL, 'prvCheckPendingReadyList') + + def test_compare_different_specificity(self): + # Different specificity: NONE < ARCHIVE < OBJ < SYMBOL + entity_a = Entity() + entity_b = Entity('libfreertos.a') + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a') + entity_b = Entity('libfreertos.a', 'croutine') + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', 'croutine') + entity_b = Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList') + self.assertLess(entity_a, entity_b) + + entity_a = Entity(Entity.ALL) + entity_b = Entity('libfreertos.a') + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', Entity.ALL) + entity_b = Entity('libfreertos.a', 'croutine') + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', 'croutine', Entity.ALL) + entity_b = Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList') + self.assertLess(entity_a, entity_b) + + def test_compare_equal(self): + # Compare equal specificities and members + entity_a = Entity() + entity_b = Entity() + self.assertEqual(entity_a, entity_b) + + entity_a = Entity('libfreertos.a') + entity_b = Entity('libfreertos.a') + self.assertEqual(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', 'croutine') + entity_b = Entity('libfreertos.a', 'croutine') + self.assertEqual(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList') + entity_b = Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList') + self.assertEqual(entity_a, entity_b) + + def test_compare_none_vs_all(self): + # Two entities might have the same specifity whether + # Entity.ALL is used or not specified; the latter is + # considered less than the former. + entity_a = Entity() + entity_b = Entity(Entity.ALL) + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a') + entity_b = Entity('libfreertos.a', Entity.ALL, Entity.ALL) + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', 'croutine') + entity_b = Entity('libfreertos.a', 'croutine', Entity.ALL) + self.assertLess(entity_a, entity_b) + + def test_compare_same_specificity(self): + # Test that entities will be compared alphabetically + # when the specificities are the same. + entity_a = Entity('libfreertos_a.a') + entity_b = Entity('libfreertos_b.a') + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos_b.a', 'croutine_a') + entity_b = Entity('libfreertos_a.a', 'croutine_b') + self.assertLess(entity_b, entity_a) + + entity_a = Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList_a') + entity_b = Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList_b') + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', 'croutine_b', 'prvCheckPendingReadyList_a') + entity_b = Entity('libfreertos.a', 'croutine_a', 'prvCheckPendingReadyList_b') + self.assertLess(entity_b, entity_a) + + entity_a = Entity('libfreertos_a.a', 'croutine_b', 'prvCheckPendingReadyList_a') + entity_b = Entity('libfreertos_b.a', 'croutine_a', 'prvCheckPendingReadyList_b') + self.assertLess(entity_a, entity_b) + + def test_compare_all_non_character(self): + # Test that Entity.ALL is not treated as an + # ordinary character in comparisons. + entity_a = Entity(Entity.ALL) + entity_b = Entity(chr(ord(Entity.ALL[0]) - 1)) + + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', Entity.ALL) + entity_b = Entity('libfreertos.a', chr(ord(Entity.ALL[0]) - 1)) + + self.assertLess(entity_a, entity_b) + + entity_a = Entity('libfreertos.a', 'croutine', '*') + entity_b = Entity('libfreertos.a', 'croutine', chr(ord(Entity.ALL[0]) - 1)) + + self.assertLess(entity_a, entity_b) + + +class EntityDBTest(unittest.TestCase): + + def setUp(self): + self.entities = EntityDB() + + with open('data/test_entity/libfreertos.a.txt') as objdump: + self.entities.add_sections_info(objdump) + + def test_get_archives(self): + archives = self.entities.get_archives() + self.assertEqual(set(archives), set(['libfreertos.a'])) + + def test_get_objs(self): + objs = self.entities.get_objects('libfreertos.a') + self.assertEqual(set(objs), set(['croutine.S.obj', 'croutine.c.obj', 'croutine.cpp.obj', 'timers.o'])) + + def test_get_sections(self): + # Needs disambugation between possible matches: croutine.S, croutine.c, croutine.cpp + with self.assertRaises(ValueError): + self.entities.get_sections('libfreertos.a', 'croutine') + + # Test disambugation works + sections = self.entities.get_sections('libfreertos.a', 'croutine.c') + expected = set(['.literal.prvCheckPendingReadyList', '.literal.prvCheckDelayedList']) + self.assertEqual(set(sections), expected) + + sections = self.entities.get_sections('libfreertos.a', 'croutine.S') + expected = set(['.debug_frame', '.debug_info', '.debug_abbrev']) + self.assertEqual(set(sections), expected) + + # Test .o extension works + sections = self.entities.get_sections('libfreertos.a', 'timers') + expected = set(['.literal.prvGetNextExpireTime', '.literal.prvInsertTimerInActiveList']) + self.assertEqual(set(sections), expected) + + def test_parsing(self): + # Tests parsing objdump with the following: + # + # - non-ascii characters + # - different architecture string + # - different column entries for each sections + # - unexpected 'comments' + with open('data/test_entity/parse_test.txt') as objdump: + self.entities.add_sections_info(objdump) + + sections = self.entities.get_sections('ěščřžýáíé.a', 'croutine') + self.assertEqual(set(sections), set(['.text', '.data', '.bss'])) + + sections = self.entities.get_sections('ěščřžýáíé.a', 'FreeRTOS-ěščřžýáíé') + self.assertEqual(set(sections), set(['.literal.ěščřžýáíé'])) + + +if __name__ == '__main__': + unittest.main() diff --git a/tools/ldgen/test/test_output_commands.py b/tools/ldgen/test/test_output_commands.py new file mode 100755 index 0000000000..fd5a5fb08e --- /dev/null +++ b/tools/ldgen/test/test_output_commands.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# +# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import sys +import unittest + +try: + from output_commands import InputSectionDesc +except ImportError: + sys.path.append('../') + from output_commands import InputSectionDesc + +from entity import Entity + +SECTIONS = ['.text', '.text.*', '.literal', '.literal.*'] + +FREERTOS = Entity('libfreertos.a') +CROUTINE = Entity('libfreertos.a', 'croutine') + + +class InputSectionDescTest(unittest.TestCase): + + def test_output_00(self): + # Test default (catch-all) command + expected = '*(.literal .literal.* .text .text.*)' + + desc = InputSectionDesc(Entity(), SECTIONS) + self.assertEqual(expected, str(desc)) + + desc = InputSectionDesc(Entity(Entity.ALL), SECTIONS) + self.assertEqual(expected, str(desc)) + + def test_output_01(self): + # Test library placement command + expected = '*libfreertos.a:(.literal .literal.* .text .text.*)' + + desc = InputSectionDesc(Entity('libfreertos.a'), SECTIONS) + self.assertEqual(expected, str(desc)) + + desc = InputSectionDesc(Entity('libfreertos.a', Entity.ALL), SECTIONS) + self.assertEqual(expected, str(desc)) + + desc = InputSectionDesc(Entity('libfreertos.a', None, Entity.ALL), SECTIONS) + self.assertEqual(expected, str(desc)) + + desc = InputSectionDesc(Entity('libfreertos.a', Entity.ALL, Entity.ALL), SECTIONS) + self.assertEqual(expected, str(desc)) + + def test_output_02(self): + # Test object placement command + expected = '*libfreertos.a:croutine.*(.literal .literal.* .text .text.*)' + + desc = InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS) + self.assertEqual(expected, str(desc)) + + desc = InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS) + self.assertEqual(expected, str(desc)) + + desc = InputSectionDesc(Entity('libfreertos.a', 'croutine', Entity.ALL), SECTIONS) + self.assertEqual(expected, str(desc)) + + # Disambugated placement + expected = '*libfreertos.a:croutine.c.*(.literal .literal.* .text .text.*)' + + desc = InputSectionDesc(Entity('libfreertos.a', 'croutine.c'), SECTIONS) + self.assertEqual(expected, str(desc)) + + def test_output_03(self): + # Invalid entity specification + with self.assertRaises(AssertionError): + InputSectionDesc(Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList'), SECTIONS) + + with self.assertRaises(AssertionError): + InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS, [Entity()]) + + with self.assertRaises(AssertionError): + InputSectionDesc(Entity('libfreertos.a', 'croutine'), SECTIONS, [Entity('libfreertos.a', 'croutine', 'prvCheckPendingReadyList')]) + + def test_output_04(self): + # Test exclusions + + # Library + expected = ('*libfreertos.a:croutine.*' + '(EXCLUDE_FILE(*libfreertos.a) ' + '.literal EXCLUDE_FILE(*libfreertos.a) ' + '.literal.* EXCLUDE_FILE(*libfreertos.a) ' + '.text EXCLUDE_FILE(*libfreertos.a) .text.*)') + desc = InputSectionDesc(CROUTINE, SECTIONS, [FREERTOS]) + self.assertEqual(expected, str(desc)) + + # Object + expected = ('*libfreertos.a:croutine.*' + '(EXCLUDE_FILE(*libfreertos.a:croutine.*) ' + '.literal EXCLUDE_FILE(*libfreertos.a:croutine.*) ' + '.literal.* EXCLUDE_FILE(*libfreertos.a:croutine.*) ' + '.text EXCLUDE_FILE(*libfreertos.a:croutine.*) .text.*)') + desc = InputSectionDesc(CROUTINE, SECTIONS, [CROUTINE]) + self.assertEqual(expected, str(desc)) + + # Multiple exclusions + expected = ('*libfreertos.a:croutine.*' + '(EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) ' + '.literal EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) ' + '.literal.* EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) ' + '.text EXCLUDE_FILE(*libfreertos.a *libfreertos.a:croutine.*) .text.*)') + desc = InputSectionDesc(CROUTINE, SECTIONS, [FREERTOS, CROUTINE]) + self.assertEqual(expected, str(desc)) + + # Disambugated exclusion + expected = ('*libfreertos.a:croutine.*' + '(EXCLUDE_FILE(*libfreertos.a:croutine.c.*) ' + '.literal EXCLUDE_FILE(*libfreertos.a:croutine.c.*) ' + '.literal.* EXCLUDE_FILE(*libfreertos.a:croutine.c.*) ' + '.text EXCLUDE_FILE(*libfreertos.a:croutine.c.*) .text.*)') + desc = InputSectionDesc(CROUTINE, SECTIONS, [Entity('libfreertos.a', 'croutine.c')]) + self.assertEqual(expected, str(desc)) + + def test_output_05(self): + # Test empty sections + expected = '*libfreertos.a:croutine.*( )' + + desc = InputSectionDesc(Entity('libfreertos.a', 'croutine'), []) + self.assertEqual(expected, str(desc)) + + +if __name__ == '__main__': + unittest.main()