generation.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. #
  2. # Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. import collections
  17. import fnmatch
  18. import itertools
  19. import os
  20. from fragments import Fragment, Mapping, Scheme, Sections
  21. from ldgen_common import LdGenFailure
  22. from pyparsing import (Group, Literal, OneOrMore, ParseException, SkipTo, Suppress, White, Word, ZeroOrMore, alphas,
  23. nums, restOfLine)
  24. class PlacementRule():
  25. """
  26. Encapsulates a generated placement rule placed under a target
  27. """
  28. DEFAULT_SPECIFICITY = 0
  29. ARCHIVE_SPECIFICITY = 1
  30. OBJECT_SPECIFICITY = 2
  31. SYMBOL_SPECIFICITY = 3
  32. class __container():
  33. def __init__(self, content):
  34. self.content = content
  35. __metadata = collections.namedtuple('__metadata', 'excludes expansions expanded')
  36. def __init__(self, archive, obj, symbol, sections, target):
  37. if archive == '*':
  38. archive = None
  39. if obj == '*':
  40. obj = None
  41. self.archive = archive
  42. self.obj = obj
  43. self.symbol = symbol
  44. self.target = target
  45. self.sections = dict()
  46. self.specificity = 0
  47. self.specificity += 1 if self.archive else 0
  48. self.specificity += 1 if (self.obj and not self.obj == '*') else 0
  49. self.specificity += 1 if self.symbol else 0
  50. for section in sections:
  51. section_data = Sections.get_section_data_from_entry(section, self.symbol)
  52. if not self.symbol:
  53. for s in section_data:
  54. metadata = self.__metadata(self.__container([]), self.__container([]), self.__container(False))
  55. self.sections[s] = metadata
  56. else:
  57. (section, expansion) = section_data
  58. if expansion:
  59. metadata = self.__metadata(self.__container([]), self.__container([expansion]), self.__container(True))
  60. self.sections[section] = metadata
  61. def get_section_names(self):
  62. return self.sections.keys()
  63. def add_exclusion(self, other, sections_infos=None):
  64. # Utility functions for this method
  65. def do_section_expansion(rule, section):
  66. if section in rule.get_section_names():
  67. sections_in_obj = sections_infos.get_obj_sections(rule.archive, rule.obj)
  68. expansions = fnmatch.filter(sections_in_obj, section)
  69. return expansions
  70. def remove_section_expansions(rule, section, expansions):
  71. existing_expansions = self.sections[section].expansions.content
  72. self.sections[section].expansions.content = [e for e in existing_expansions if e not in expansions]
  73. # Exit immediately if the exclusion to be added is more general than this rule.
  74. if not other.is_more_specific_rule_of(self):
  75. return
  76. for section in self.get_sections_intersection(other):
  77. if(other.specificity == PlacementRule.SYMBOL_SPECIFICITY):
  78. # If this sections has not been expanded previously, expand now and keep track.
  79. previously_expanded = self.sections[section].expanded.content
  80. if not previously_expanded:
  81. expansions = do_section_expansion(self, section)
  82. if expansions:
  83. self.sections[section].expansions.content = expansions
  84. self.sections[section].expanded.content = True
  85. previously_expanded = True
  86. # Remove the sections corresponding to the symbol name
  87. remove_section_expansions(self, section, other.sections[section].expansions.content)
  88. # If it has been expanded previously but now the expansions list is empty,
  89. # it means adding exclusions has exhausted the list. Remove the section entirely.
  90. if previously_expanded and not self.sections[section].expanded.content:
  91. del self.sections[section]
  92. else:
  93. # A rule section can have multiple rule sections excluded from it. Get the
  94. # most specific rule from the list, and if an even more specific rule is found,
  95. # replace it entirely. Otherwise, keep appending.
  96. exclusions = self.sections[section].excludes
  97. exclusions_list = exclusions.content if exclusions.content is not None else []
  98. exclusions_to_remove = filter(lambda r: r.is_more_specific_rule_of(other), exclusions_list)
  99. remaining_exclusions = [e for e in exclusions_list if e not in exclusions_to_remove]
  100. remaining_exclusions.append(other)
  101. self.sections[section].excludes.content = remaining_exclusions
  102. def get_sections_intersection(self, other):
  103. return set(self.sections.keys()).intersection(set(other.sections.keys()))
  104. def is_more_specific_rule_of(self, other):
  105. if (self.specificity <= other.specificity):
  106. return False
  107. # Compare archive, obj and target
  108. for entity_index in range(1, other.specificity + 1):
  109. if self[entity_index] != other[entity_index] and other[entity_index] is not None:
  110. return False
  111. return True
  112. def maps_same_entities_as(self, other):
  113. if self.specificity != other.specificity:
  114. return False
  115. # Compare archive, obj and target
  116. for entity_index in range(1, other.specificity + 1):
  117. if self[entity_index] != other[entity_index] and other[entity_index] is not None:
  118. return False
  119. return True
  120. def __getitem__(self, key):
  121. if key == PlacementRule.ARCHIVE_SPECIFICITY:
  122. return self.archive
  123. elif key == PlacementRule.OBJECT_SPECIFICITY:
  124. return self.obj
  125. elif key == PlacementRule.SYMBOL_SPECIFICITY:
  126. return self.symbol
  127. else:
  128. return None
  129. def __str__(self):
  130. sorted_sections = sorted(self.get_section_names())
  131. sections_string = list()
  132. for section in sorted_sections:
  133. exclusions = self.sections[section].excludes.content
  134. exclusion_string = None
  135. if exclusions:
  136. exclusion_string = ' '.join(map(lambda e: '*' + e.archive + (':' + e.obj + '.*' if e.obj else ''), exclusions))
  137. exclusion_string = 'EXCLUDE_FILE(' + exclusion_string + ')'
  138. else:
  139. exclusion_string = ''
  140. section_string = None
  141. exclusion_section_string = None
  142. section_expansions = self.sections[section].expansions.content
  143. section_expanded = self.sections[section].expanded.content
  144. if section_expansions and section_expanded:
  145. section_string = ' '.join(section_expansions)
  146. exclusion_section_string = section_string
  147. else:
  148. section_string = section
  149. exclusion_section_string = exclusion_string + ' ' + section_string
  150. sections_string.append(exclusion_section_string)
  151. sections_string = ' '.join(sections_string)
  152. archive = str(self.archive) if self.archive else ''
  153. obj = (str(self.obj) + ('.*' if self.obj else '')) if self.obj else ''
  154. # Handle output string generation based on information available
  155. if self.specificity == PlacementRule.DEFAULT_SPECIFICITY:
  156. rule_string = '*(%s)' % (sections_string)
  157. elif self.specificity == PlacementRule.ARCHIVE_SPECIFICITY:
  158. rule_string = '*%s:(%s)' % (archive, sections_string)
  159. else:
  160. rule_string = '*%s:%s(%s)' % (archive, obj, sections_string)
  161. return rule_string
  162. def __eq__(self, other):
  163. if id(self) == id(other):
  164. return True
  165. def exclusions_set(exclusions):
  166. exclusions_set = {(e.archive, e.obj, e.symbol, e.target) for e in exclusions}
  167. return exclusions_set
  168. if self.archive != other.archive:
  169. return False
  170. if self.obj != other.obj:
  171. return False
  172. if self.symbol != other.symbol:
  173. return False
  174. if set(self.sections.keys()) != set(other.sections.keys()):
  175. return False
  176. for (section, metadata) in self.sections.items():
  177. self_meta = metadata
  178. other_meta = other.sections[section]
  179. if exclusions_set(self_meta.excludes.content) != exclusions_set(other_meta.excludes.content):
  180. return False
  181. if set(self_meta.expansions.content) != set(other_meta.expansions.content):
  182. return False
  183. return True
  184. def __ne__(self, other):
  185. return not self.__eq__(other)
  186. def __iter__(self):
  187. yield self.archive
  188. yield self.obj
  189. yield self.symbol
  190. raise StopIteration
  191. class GenerationModel:
  192. """
  193. Implements generation of placement rules based on collected sections, scheme and mapping fragment.
  194. """
  195. DEFAULT_SCHEME = 'default'
  196. def __init__(self, check_mappings=False, check_mapping_exceptions=None):
  197. self.schemes = {}
  198. self.sections = {}
  199. self.mappings = {}
  200. self.check_mappings = check_mappings
  201. if check_mapping_exceptions:
  202. self.check_mapping_exceptions = check_mapping_exceptions
  203. else:
  204. self.check_mapping_exceptions = []
  205. def _add_mapping_rules(self, archive, obj, symbol, scheme_name, scheme_dict, rules):
  206. # Use an ordinary dictionary to raise exception on non-existing keys
  207. temp_dict = dict(scheme_dict)
  208. sections_bucket = temp_dict[scheme_name]
  209. for (target, sections) in sections_bucket.items():
  210. section_entries = []
  211. for section in sections:
  212. section_entries.extend(section.entries)
  213. rule = PlacementRule(archive, obj, symbol, section_entries, target)
  214. if rule not in rules:
  215. rules.append(rule)
  216. def _build_scheme_dictionary(self):
  217. scheme_dictionary = collections.defaultdict(dict)
  218. # Collect sections into buckets based on target name
  219. for scheme in self.schemes.values():
  220. sections_bucket = collections.defaultdict(list)
  221. for (sections_name, target_name) in scheme.entries:
  222. # Get the sections under the bucket 'target_name'. If this bucket does not exist
  223. # is is created automatically
  224. sections_in_bucket = sections_bucket[target_name]
  225. try:
  226. sections = self.sections[sections_name]
  227. except KeyError:
  228. message = GenerationException.UNDEFINED_REFERENCE + " to sections '" + sections + "'."
  229. raise GenerationException(message, scheme)
  230. sections_in_bucket.append(sections)
  231. scheme_dictionary[scheme.name] = sections_bucket
  232. # Search for and raise exception on first instance of sections mapped to multiple targets
  233. for (scheme_name, sections_bucket) in scheme_dictionary.items():
  234. for sections_a, sections_b in itertools.combinations(sections_bucket.values(), 2):
  235. set_a = set()
  236. set_b = set()
  237. for sections in sections_a:
  238. set_a.update(sections.entries)
  239. for sections in sections_b:
  240. set_b.update(sections.entries)
  241. intersection = set_a.intersection(set_b)
  242. # If the intersection is a non-empty set, it means sections are mapped to multiple
  243. # targets. Raise exception.
  244. if intersection:
  245. scheme = self.schemes[scheme_name]
  246. message = 'Sections ' + str(intersection) + ' mapped to multiple targets.'
  247. raise GenerationException(message, scheme)
  248. return scheme_dictionary
  249. def generate_rules(self, sections_infos):
  250. scheme_dictionary = self._build_scheme_dictionary()
  251. # Generate default rules
  252. default_rules = list()
  253. self._add_mapping_rules(None, None, None, GenerationModel.DEFAULT_SCHEME, scheme_dictionary, default_rules)
  254. all_mapping_rules = collections.defaultdict(list)
  255. # Generate rules based on mapping fragments
  256. for mapping in self.mappings.values():
  257. archive = mapping.archive
  258. mapping_rules = all_mapping_rules[archive]
  259. for (obj, symbol, scheme_name) in mapping.entries:
  260. try:
  261. if not (obj == Mapping.MAPPING_ALL_OBJECTS and symbol is None and
  262. scheme_name == GenerationModel.DEFAULT_SCHEME):
  263. if self.check_mappings and mapping.name not in self.check_mapping_exceptions:
  264. if not obj == Mapping.MAPPING_ALL_OBJECTS:
  265. obj_sections = sections_infos.get_obj_sections(archive, obj)
  266. if not obj_sections:
  267. message = "'%s:%s' not found" % (archive, obj)
  268. raise GenerationException(message, mapping)
  269. if symbol:
  270. obj_sym = fnmatch.filter(obj_sections, '*%s' % symbol)
  271. if not obj_sym:
  272. message = "'%s:%s %s' not found" % (archive, obj, symbol)
  273. raise GenerationException(message, mapping)
  274. self._add_mapping_rules(archive, obj, symbol, scheme_name, scheme_dictionary, mapping_rules)
  275. except KeyError:
  276. message = GenerationException.UNDEFINED_REFERENCE + " to scheme '" + scheme_name + "'."
  277. raise GenerationException(message, mapping)
  278. # Detect rule conflicts
  279. for mapping_rules in all_mapping_rules.items():
  280. self._detect_conflicts(mapping_rules)
  281. # Add exclusions
  282. for mapping_rules in all_mapping_rules.values():
  283. self._create_exclusions(mapping_rules, default_rules, sections_infos)
  284. placement_rules = collections.defaultdict(list)
  285. # Add the default rules grouped by target
  286. for default_rule in default_rules:
  287. existing_rules = placement_rules[default_rule.target]
  288. if default_rule.get_section_names():
  289. existing_rules.append(default_rule)
  290. archives = sorted(all_mapping_rules.keys())
  291. for archive in archives:
  292. # Add the mapping rules grouped by target
  293. mapping_rules = sorted(all_mapping_rules[archive], key=lambda m: (m.specificity, str(m)))
  294. for mapping_rule in mapping_rules:
  295. existing_rules = placement_rules[mapping_rule.target]
  296. if mapping_rule.get_section_names():
  297. existing_rules.append(mapping_rule)
  298. return placement_rules
  299. def _detect_conflicts(self, rules):
  300. (archive, rules_list) = rules
  301. for specificity in range(0, PlacementRule.OBJECT_SPECIFICITY + 1):
  302. rules_with_specificity = filter(lambda r: r.specificity == specificity, rules_list)
  303. for rule_a, rule_b in itertools.combinations(rules_with_specificity, 2):
  304. intersections = rule_a.get_sections_intersection(rule_b)
  305. if intersections and rule_a.maps_same_entities_as(rule_b):
  306. rules_string = str([str(rule_a), str(rule_b)])
  307. message = 'Rules ' + rules_string + ' map sections ' + str(list(intersections)) + ' into multiple targets.'
  308. raise GenerationException(message)
  309. def _create_extra_rules(self, rules):
  310. # This function generates extra rules for symbol specific rules. The reason for generating extra rules is to isolate,
  311. # as much as possible, rules that require expansion. Particularly, object specific extra rules are generated.
  312. rules_to_process = sorted(rules, key=lambda r: r.specificity)
  313. symbol_specific_rules = list(filter(lambda r: r.specificity == PlacementRule.SYMBOL_SPECIFICITY, rules_to_process))
  314. extra_rules = dict()
  315. for symbol_specific_rule in symbol_specific_rules:
  316. extra_rule_candidate = {s: None for s in symbol_specific_rule.get_section_names()}
  317. super_rules = filter(lambda r: symbol_specific_rule.is_more_specific_rule_of(r), rules_to_process)
  318. # Take a look at the existing rules that are more general than the current symbol-specific rule.
  319. # Only generate an extra rule if there is no existing object specific rule for that section
  320. for super_rule in super_rules:
  321. intersections = symbol_specific_rule.get_sections_intersection(super_rule)
  322. for intersection in intersections:
  323. if super_rule.specificity != PlacementRule.OBJECT_SPECIFICITY:
  324. extra_rule_candidate[intersection] = super_rule
  325. else:
  326. extra_rule_candidate[intersection] = None
  327. # Generate the extra rules for the symbol specific rule section, keeping track of the generated extra rules
  328. for (section, section_rule) in extra_rule_candidate.items():
  329. if section_rule:
  330. extra_rule = None
  331. extra_rules_key = (symbol_specific_rule.archive, symbol_specific_rule.obj, section_rule.target)
  332. try:
  333. extra_rule = extra_rules[extra_rules_key]
  334. if section not in extra_rule.get_section_names():
  335. new_rule = PlacementRule(extra_rule.archive, extra_rule.obj, extra_rule.symbol,
  336. list(extra_rule.get_section_names()) + [section], extra_rule.target)
  337. extra_rules[extra_rules_key] = new_rule
  338. except KeyError:
  339. extra_rule = PlacementRule(symbol_specific_rule.archive, symbol_specific_rule.obj, None, [section], section_rule.target)
  340. extra_rules[extra_rules_key] = extra_rule
  341. return extra_rules.values()
  342. def _create_exclusions(self, mapping_rules, default_rules, sections_info):
  343. rules = list(default_rules)
  344. rules.extend(mapping_rules)
  345. extra_rules = self._create_extra_rules(rules)
  346. mapping_rules.extend(extra_rules)
  347. rules.extend(extra_rules)
  348. # Sort the rules by means of how specific they are. Sort by specificity from lowest to highest
  349. # * -> lib:* -> lib:obj -> lib:obj:symbol
  350. sorted_rules = sorted(rules, key=lambda r: r.specificity)
  351. # Now that the rules have been sorted, loop through each rule, and then loop
  352. # through rules below it (higher indeces), adding exclusions whenever appropriate.
  353. for general_rule in sorted_rules:
  354. for specific_rule in reversed(sorted_rules):
  355. if (specific_rule.specificity > general_rule.specificity and
  356. specific_rule.specificity != PlacementRule.SYMBOL_SPECIFICITY) or \
  357. (specific_rule.specificity == PlacementRule.SYMBOL_SPECIFICITY and
  358. general_rule.specificity == PlacementRule.OBJECT_SPECIFICITY):
  359. general_rule.add_exclusion(specific_rule, sections_info)
  360. def add_fragments_from_file(self, fragment_file):
  361. for fragment in fragment_file.fragments:
  362. dict_to_append_to = None
  363. if isinstance(fragment, Mapping) and fragment.deprecated and fragment.name in self.mappings.keys():
  364. self.mappings[fragment.name].entries |= fragment.entries
  365. else:
  366. if isinstance(fragment, Scheme):
  367. dict_to_append_to = self.schemes
  368. elif isinstance(fragment, Sections):
  369. dict_to_append_to = self.sections
  370. else:
  371. dict_to_append_to = self.mappings
  372. # Raise exception when the fragment of the same type is already in the stored fragments
  373. if fragment.name in dict_to_append_to.keys():
  374. stored = dict_to_append_to[fragment.name].path
  375. new = fragment.path
  376. message = "Duplicate definition of fragment '%s' found in %s and %s." % (fragment.name, stored, new)
  377. raise GenerationException(message)
  378. dict_to_append_to[fragment.name] = fragment
  379. class TemplateModel:
  380. """
  381. Encapsulates a linker script template file. Finds marker syntax and handles replacement to generate the
  382. final output.
  383. """
  384. Marker = collections.namedtuple('Marker', 'target indent rules')
  385. def __init__(self, template_file):
  386. self.members = []
  387. self.file = os.path.realpath(template_file.name)
  388. self._generate_members(template_file)
  389. def _generate_members(self, template_file):
  390. lines = template_file.readlines()
  391. target = Fragment.IDENTIFIER
  392. reference = Suppress('mapping') + Suppress('[') + target.setResultsName('target') + Suppress(']')
  393. pattern = White(' \t').setResultsName('indent') + reference
  394. # Find the markers in the template file line by line. If line does not match marker grammar,
  395. # set it as a literal to be copied as is to the output file.
  396. for line in lines:
  397. try:
  398. parsed = pattern.parseString(line)
  399. indent = parsed.indent
  400. target = parsed.target
  401. marker = TemplateModel.Marker(target, indent, [])
  402. self.members.append(marker)
  403. except ParseException:
  404. # Does not match marker syntax
  405. self.members.append(line)
  406. def fill(self, mapping_rules):
  407. for member in self.members:
  408. target = None
  409. try:
  410. target = member.target
  411. rules = member.rules
  412. del rules[:]
  413. rules.extend(mapping_rules[target])
  414. except KeyError:
  415. message = GenerationException.UNDEFINED_REFERENCE + " to target '" + target + "'."
  416. raise GenerationException(message)
  417. except AttributeError:
  418. pass
  419. def write(self, output_file):
  420. # Add information that this is a generated file.
  421. output_file.write('/* Automatically generated file; DO NOT EDIT */\n')
  422. output_file.write('/* Espressif IoT Development Framework Linker Script */\n')
  423. output_file.write('/* Generated from: %s */\n' % self.file)
  424. output_file.write('\n')
  425. # Do the text replacement
  426. for member in self.members:
  427. try:
  428. indent = member.indent
  429. rules = member.rules
  430. for rule in rules:
  431. generated_line = ''.join([indent, str(rule), '\n'])
  432. output_file.write(generated_line)
  433. except AttributeError:
  434. output_file.write(member)
  435. class GenerationException(LdGenFailure):
  436. """
  437. Exception for linker script generation failures such as undefined references/ failure to
  438. evaluate conditions, duplicate mappings, etc.
  439. """
  440. UNDEFINED_REFERENCE = 'Undefined reference'
  441. def __init__(self, message, fragment=None):
  442. self.fragment = fragment
  443. self.message = message
  444. def __str__(self):
  445. if self.fragment:
  446. return "%s\nIn fragment '%s' defined in '%s'." % (self.message, self.fragment.name, self.fragment.path)
  447. else:
  448. return self.message
  449. class SectionsInfo(dict):
  450. """
  451. Encapsulates an output of objdump. Contains information about the static library sections
  452. and names
  453. """
  454. __info = collections.namedtuple('__info', 'filename content')
  455. def __init__(self):
  456. self.sections = dict()
  457. def add_sections_info(self, sections_info_dump):
  458. first_line = sections_info_dump.readline()
  459. archive_path = (Literal('In archive').suppress() +
  460. White().suppress() +
  461. # trim the colon and line ending characters from archive_path
  462. restOfLine.setResultsName('archive_path').setParseAction(lambda s, loc, toks: s.rstrip(':\n\r ')))
  463. parser = archive_path
  464. results = None
  465. try:
  466. results = parser.parseString(first_line, parseAll=True)
  467. except ParseException as p:
  468. raise ParseException('Parsing sections info for library ' + sections_info_dump.name + ' failed. ' + p.msg)
  469. archive = os.path.basename(results.archive_path)
  470. self.sections[archive] = SectionsInfo.__info(sections_info_dump.name, sections_info_dump.read())
  471. def _get_infos_from_file(self, info):
  472. # {object}: file format elf32-xtensa-le
  473. object_line = SkipTo(':').setResultsName('object') + Suppress(restOfLine)
  474. # Sections:
  475. # Idx Name ...
  476. section_start = Suppress(Literal('Sections:'))
  477. section_header = Suppress(OneOrMore(Word(alphas)))
  478. # 00 {section} 0000000 ...
  479. # CONTENTS, ALLOC, ....
  480. section_entry = Suppress(Word(nums)) + SkipTo(' ') + Suppress(restOfLine) + \
  481. Suppress(ZeroOrMore(Word(alphas) + Literal(',')) + Word(alphas))
  482. content = Group(object_line + section_start + section_header + Group(OneOrMore(section_entry)).setResultsName('sections'))
  483. parser = Group(ZeroOrMore(content)).setResultsName('contents')
  484. results = None
  485. try:
  486. results = parser.parseString(info.content, parseAll=True)
  487. except ParseException as p:
  488. raise ParseException('Unable to parse section info file ' + info.filename + '. ' + p.msg)
  489. return results
  490. def get_obj_sections(self, archive, obj):
  491. res = []
  492. try:
  493. stored = self.sections[archive]
  494. # Parse the contents of the sections file on-demand,
  495. # save the result for later
  496. if not isinstance(stored, dict):
  497. parsed = self._get_infos_from_file(stored)
  498. stored = dict()
  499. for content in parsed.contents:
  500. sections = list(map(lambda s: s, content.sections))
  501. stored[content.object] = sections
  502. self.sections[archive] = stored
  503. try:
  504. res = stored[obj + '.o']
  505. except KeyError:
  506. try:
  507. res = stored[obj + '.c.obj']
  508. except KeyError:
  509. try:
  510. res = stored[obj + '.cpp.obj']
  511. except KeyError:
  512. res = stored[obj + '.S.obj']
  513. except KeyError:
  514. pass
  515. return res