CreateSectionTable.py 5.9 KB

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