/ tools / unit-test-app / tools / CreateSectionTable.py
CreateSectionTable.py
  1  # This file is used to process section data generated by `objdump -s`
  2  import re
  3  
  4  
  5  class Section(object):
  6      """
  7      One Section of section table. contains info about section name, address and raw data
  8      """
  9      SECTION_START_PATTERN = re.compile(b"Contents of section (.+?):")
 10      DATA_PATTERN = re.compile(b"([0-9a-f]{4,8})")
 11  
 12      def __init__(self, name, start_address, data):
 13          self.name = name
 14          self.start_address = start_address
 15          self.data = data
 16  
 17      def __contains__(self, item):
 18          """ check if the section name and address match this section """
 19          if (item["section"] == self.name or item["section"] == "any") \
 20                  and (self.start_address <= item["address"] < (self.start_address + len(self.data))):
 21              return True
 22          else:
 23              return False
 24  
 25      def __getitem__(self, item):
 26          """
 27          process slice.
 28          convert absolute address to relative address in current section and return slice result
 29          """
 30          if isinstance(item, int):
 31              return self.data[item - self.start_address]
 32          elif isinstance(item, slice):
 33              start = item.start if item.start is None else item.start - self.start_address
 34              stop = item.stop if item.stop is None else item.stop - self.start_address
 35              return self.data[start:stop]
 36          return self.data[item]
 37  
 38      def __str__(self):
 39          return "%s [%08x - %08x]" % (self.name, self.start_address, self.start_address + len(self.data))
 40  
 41      __repr__ = __str__
 42  
 43      @classmethod
 44      def parse_raw_data(cls, raw_data):
 45          """
 46          process raw data generated by `objdump -s`, create section and return un-processed lines
 47          :param raw_data: lines of raw data generated by `objdump -s`
 48          :return: one section, un-processed lines
 49          """
 50          name = ""
 51          data = ""
 52          start_address = 0
 53          # first find start line
 54          for i, line in enumerate(raw_data):
 55              if b"Contents of section " in line:  # do strcmp first to speed up
 56                  match = cls.SECTION_START_PATTERN.search(line)
 57                  if match is not None:
 58                      name = match.group(1)
 59                      raw_data = raw_data[i + 1:]
 60                      break
 61          else:
 62              # do some error handling
 63              raw_data = [b""]  # add a dummy first data line
 64  
 65          def process_data_line(line_to_process):
 66              # first remove the ascii part
 67              hex_part = line_to_process.split(b"  ")[0]
 68              # process rest part
 69              data_list = cls.DATA_PATTERN.findall(hex_part)
 70              try:
 71                  _address = int(data_list[0], base=16)
 72              except IndexError:
 73                  _address = -1
 74  
 75              def hex_to_str(hex_data):
 76                  if len(hex_data) % 2 == 1:
 77                      hex_data = b"0" + hex_data  # append zero at the beginning
 78                  _length = len(hex_data)
 79                  return "".join([chr(int(hex_data[_i:_i + 2], base=16))
 80                                  for _i in range(0, _length, 2)])
 81  
 82              return _address, "".join([hex_to_str(x) for x in data_list[1:]])
 83  
 84          # handle first line:
 85          address, _data = process_data_line(raw_data[0])
 86          if address != -1:
 87              start_address = address
 88              data += _data
 89              raw_data = raw_data[1:]
 90              for i, line in enumerate(raw_data):
 91                  address, _data = process_data_line(line)
 92                  if address == -1:
 93                      raw_data = raw_data[i:]
 94                      break
 95                  else:
 96                      data += _data
 97          else:
 98              # do error handling
 99              raw_data = []
100  
101          section = cls(name, start_address, data) if start_address != -1 else None
102          unprocessed_data = None if len(raw_data) == 0 else raw_data
103          return section, unprocessed_data
104  
105  
106  class SectionTable(object):
107      """ elf section table """
108  
109      def __init__(self, file_name):
110          with open(file_name, "rb") as f:
111              raw_data = f.readlines()
112          self.table = []
113          while raw_data:
114              section, raw_data = Section.parse_raw_data(raw_data)
115              self.table.append(section)
116  
117      def get_unsigned_int(self, section, address, size=4, endian="LE"):
118          """
119          get unsigned int from section table
120          :param section: section name; use "any" will only match with address
121          :param address: start address
122          :param size: size in bytes
123          :param endian: LE or BE
124          :return: int or None
125          """
126          if address % 4 != 0 or size % 4 != 0:
127              print("warning: try to access without 4 bytes aligned")
128          key = {"address": address, "section": section}
129          for section in self.table:
130              if key in section:
131                  tmp = section[address:address + size]
132                  value = 0
133                  for i in range(size):
134                      if endian == "LE":
135                          value += ord(tmp[i]) << (i * 8)
136                      elif endian == "BE":
137                          value += ord(tmp[i]) << ((size - i - 1) * 8)
138                      else:
139                          print("only support LE or BE for parameter endian")
140                          assert False
141                  break
142          else:
143              value = None
144          return value
145  
146      def get_string(self, section, address):
147          """
148          get string ('\0' terminated) from section table
149          :param section: section name; use "any" will only match with address
150          :param address: start address
151          :return: string or None
152          """
153          value = None
154          key = {"address": address, "section": section}
155          for section in self.table:
156              if key in section:
157                  value = section[address:]
158                  for i, c in enumerate(value):
159                      if c == '\0':
160                          value = value[:i]
161                          break
162                  break
163          return value