xtensa.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #
  2. # Copyright 2021 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. from construct import Int16ul, Int32ul, Int64ul, Struct
  17. from . import ESPCoreDumpLoaderError, _ArchMethodsBase, _TargetMethodsBase
  18. INVALID_CAUSE_VALUE = 0xFFFF
  19. XCHAL_EXCCAUSE_NUM = 64
  20. # Exception cause dictionary to get translation of exccause register
  21. # From 4.4.1.5 table 4-64 Exception Causes of Xtensa
  22. # Instruction Set Architecture (ISA) Reference Manual
  23. XTENSA_EXCEPTION_CAUSE_DICT = {
  24. 0: ('IllegalInstructionCause', 'Illegal instruction'),
  25. 1: ('SyscallCause', 'SYSCALL instruction'),
  26. 2: ('InstructionFetchErrorCause',
  27. 'Processor internal physical address or data error during instruction fetch. (See EXCVADDR for more information)'),
  28. 3: ('LoadStoreErrorCause',
  29. 'Processor internal physical address or data error during load or store. (See EXCVADDR for more information)'),
  30. 4: ('Level1InterruptCause', 'Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register'),
  31. 5: ('AllocaCause', 'MOVSP instruction, if caller`s registers are not in the register file'),
  32. 6: ('IntegerDivideByZeroCause', 'QUOS: QUOU, REMS: or REMU divisor operand is zero'),
  33. 8: ('PrivilegedCause', 'Attempt to execute a privileged operation when CRING ? 0'),
  34. 9: ('LoadStoreAlignmentCause', 'Load or store to an unaligned address. (See EXCVADDR for more information)'),
  35. 12: ('InstrPIFDataErrorCause', 'PIF data error during instruction fetch. (See EXCVADDR for more information)'),
  36. 13: ('LoadStorePIFDataErrorCause',
  37. 'Synchronous PIF data error during LoadStore access. (See EXCVADDR for more information)'),
  38. 14: ('InstrPIFAddrErrorCause', 'PIF address error during instruction fetch. (See EXCVADDR for more information)'),
  39. 15: ('LoadStorePIFAddrErrorCause',
  40. 'Synchronous PIF address error during LoadStore access. (See EXCVADDR for more information)'),
  41. 16: ('InstTLBMissCause', 'Error during Instruction TLB refill. (See EXCVADDR for more information)'),
  42. 17: ('InstTLBMultiHitCause', 'Multiple instruction TLB entries matched. (See EXCVADDR for more information)'),
  43. 18: ('InstFetchPrivilegeCause',
  44. 'An instruction fetch referenced a virtual address at a ring level less than CRING. (See EXCVADDR for more information)'),
  45. 20: ('InstFetchProhibitedCause',
  46. 'An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch (EXCVADDR).'),
  47. 24: ('LoadStoreTLBMissCause', 'Error during TLB refill for a load or store. (See EXCVADDR for more information)'),
  48. 25: ('LoadStoreTLBMultiHitCause',
  49. 'Multiple TLB entries matched for a load or store. (See EXCVADDR for more information)'),
  50. 26: ('LoadStorePrivilegeCause',
  51. 'A load or store referenced a virtual address at a ring level less than CRING. (See EXCVADDR for more information)'),
  52. 28: ('LoadProhibitedCause',
  53. 'A load referenced a page mapped with an attribute that does not permit loads. (See EXCVADDR for more information)'),
  54. 29: ('StoreProhibitedCause',
  55. 'A store referenced a page mapped with an attribute that does not permit stores [Region Protection Option or MMU Option].'),
  56. 32: ('Coprocessor0Disabled', 'Coprocessor 0 instruction when cp0 disabled'),
  57. 33: ('Coprocessor1Disabled', 'Coprocessor 1 instruction when cp1 disabled'),
  58. 34: ('Coprocessor2Disabled', 'Coprocessor 2 instruction when cp2 disabled'),
  59. 35: ('Coprocessor3Disabled', 'Coprocessor 3 instruction when cp3 disabled'),
  60. 36: ('Coprocessor4Disabled', 'Coprocessor 4 instruction when cp4 disabled'),
  61. 37: ('Coprocessor5Disabled', 'Coprocessor 5 instruction when cp5 disabled'),
  62. 38: ('Coprocessor6Disabled', 'Coprocessor 6 instruction when cp6 disabled'),
  63. 39: ('Coprocessor7Disabled', 'Coprocessor 7 instruction when cp7 disabled'),
  64. INVALID_CAUSE_VALUE: (
  65. 'InvalidCauseRegister', 'Invalid EXCCAUSE register value or current task is broken and was skipped'),
  66. # ESP panic pseudo reasons
  67. XCHAL_EXCCAUSE_NUM + 0: ('UnknownException', 'Unknown exception'),
  68. XCHAL_EXCCAUSE_NUM + 1: ('DebugException', 'Unhandled debug exception'),
  69. XCHAL_EXCCAUSE_NUM + 2: ('DoubleException', 'Double exception'),
  70. XCHAL_EXCCAUSE_NUM + 3: ('KernelException', 'Unhandled kernel exception'),
  71. XCHAL_EXCCAUSE_NUM + 4: ('CoprocessorException', 'Coprocessor exception'),
  72. XCHAL_EXCCAUSE_NUM + 5: ('InterruptWDTTimoutCPU0', 'Interrupt wdt timeout on CPU0'),
  73. XCHAL_EXCCAUSE_NUM + 6: ('InterruptWDTTimoutCPU1', 'Interrupt wdt timeout on CPU1'),
  74. XCHAL_EXCCAUSE_NUM + 7: ('CacheError', 'Cache disabled but cached memory region accessed'),
  75. }
  76. class XtensaRegisters(object):
  77. # extra regs IDs used in EXTRA_INFO note
  78. EXCCAUSE_IDX = 0
  79. EXCVADDR_IDX = 1
  80. EPS2_IDX = 2
  81. EPS3_IDX = 3
  82. EPS4_IDX = 4
  83. EPS5_IDX = 5
  84. EPS6_IDX = 6
  85. EPS7_IDX = 7
  86. EPC1_IDX = 8
  87. EPC2_IDX = 9
  88. EPC3_IDX = 10
  89. EPC4_IDX = 11
  90. EPC5_IDX = 12
  91. EPC6_IDX = 13
  92. EPC7_IDX = 14
  93. @property
  94. def registers(self):
  95. return {k: v for k, v in self.__class__.__dict__.items()
  96. if not k.startswith('__') and isinstance(v, int)}
  97. # Following structs are based on source code
  98. # IDF_PATH/components/espcoredump/src/core_dump_port.c
  99. XtensaPrStatus = Struct(
  100. 'si_signo' / Int32ul,
  101. 'si_code' / Int32ul,
  102. 'si_errno' / Int32ul,
  103. 'pr_cursig' / Int16ul,
  104. 'pr_pad0' / Int16ul,
  105. 'pr_sigpend' / Int32ul,
  106. 'pr_sighold' / Int32ul,
  107. 'pr_pid' / Int32ul,
  108. 'pr_ppid' / Int32ul,
  109. 'pr_pgrp' / Int32ul,
  110. 'pr_sid' / Int32ul,
  111. 'pr_utime' / Int64ul,
  112. 'pr_stime' / Int64ul,
  113. 'pr_cutime' / Int64ul,
  114. 'pr_cstime' / Int64ul,
  115. )
  116. def print_exc_regs_info(extra_info):
  117. """
  118. Print the register info by parsing extra_info
  119. :param extra_info: extra info data str
  120. :return: None
  121. """
  122. exccause = extra_info[1 + 2 * XtensaRegisters.EXCCAUSE_IDX + 1]
  123. exccause_str = XTENSA_EXCEPTION_CAUSE_DICT.get(exccause)
  124. if not exccause_str:
  125. exccause_str = ('Invalid EXCCAUSE code', 'Invalid EXCAUSE description or not found.')
  126. print('exccause 0x%x (%s)' % (exccause, exccause_str[0]))
  127. print('excvaddr 0x%x' % extra_info[1 + 2 * XtensaRegisters.EXCVADDR_IDX + 1])
  128. print('epc1 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPC1_IDX + 1])
  129. print('epc2 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPC2_IDX + 1])
  130. print('epc3 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPC3_IDX + 1])
  131. print('epc4 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPC4_IDX + 1])
  132. print('epc5 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPC5_IDX + 1])
  133. print('epc6 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPC6_IDX + 1])
  134. print('epc7 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPC7_IDX + 1])
  135. print('eps2 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPS2_IDX + 1])
  136. print('eps3 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPS3_IDX + 1])
  137. print('eps4 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPS4_IDX + 1])
  138. print('eps5 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPS5_IDX + 1])
  139. print('eps6 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPS6_IDX + 1])
  140. print('eps7 0x%x' % extra_info[1 + 2 * XtensaRegisters.EPS7_IDX + 1])
  141. # from "gdb/xtensa-tdep.h"
  142. # typedef struct
  143. # {
  144. # 0 xtensa_elf_greg_t pc;
  145. # 1 xtensa_elf_greg_t ps;
  146. # 2 xtensa_elf_greg_t lbeg;
  147. # 3 xtensa_elf_greg_t lend;
  148. # 4 xtensa_elf_greg_t lcount;
  149. # 5 xtensa_elf_greg_t sar;
  150. # 6 xtensa_elf_greg_t windowstart;
  151. # 7 xtensa_elf_greg_t windowbase;
  152. # 8..63 xtensa_elf_greg_t reserved[8+48];
  153. # 64 xtensa_elf_greg_t ar[64];
  154. # } xtensa_elf_gregset_t;
  155. REG_PC_IDX = 0
  156. REG_PS_IDX = 1
  157. REG_LB_IDX = 2
  158. REG_LE_IDX = 3
  159. REG_LC_IDX = 4
  160. REG_SAR_IDX = 5
  161. # REG_WS_IDX = 6
  162. # REG_WB_IDX = 7
  163. REG_AR_START_IDX = 64
  164. # REG_AR_NUM = 64
  165. # FIXME: acc to xtensa_elf_gregset_t number of regs must be 128,
  166. # but gdb complains when it less then 129
  167. REG_NUM = 129
  168. # XT_SOL_EXIT = 0
  169. XT_SOL_PC = 1
  170. XT_SOL_PS = 2
  171. # XT_SOL_NEXT = 3
  172. XT_SOL_AR_START = 4
  173. XT_SOL_AR_NUM = 4
  174. # XT_SOL_FRMSZ = 8
  175. XT_STK_EXIT = 0
  176. XT_STK_PC = 1
  177. XT_STK_PS = 2
  178. XT_STK_AR_START = 3
  179. XT_STK_AR_NUM = 16
  180. XT_STK_SAR = 19
  181. XT_STK_EXCCAUSE = 20
  182. XT_STK_EXCVADDR = 21
  183. XT_STK_LBEG = 22
  184. XT_STK_LEND = 23
  185. XT_STK_LCOUNT = 24
  186. XT_STK_FRMSZ = 25
  187. class _TargetMethodsESP32(_TargetMethodsBase):
  188. @staticmethod
  189. def tcb_is_sane(tcb_addr, tcb_size):
  190. return not (tcb_addr < 0x3ffae000 or (tcb_addr + tcb_size) > 0x40000000)
  191. @staticmethod
  192. def stack_is_sane(sp):
  193. return not (sp < 0x3ffae010 or sp > 0x3fffffff)
  194. @staticmethod
  195. def addr_is_fake(addr):
  196. return (0x20000000 <= addr < 0x3f3fffff) or addr >= 0x80000000
  197. class _ArchMethodsXtensa(_ArchMethodsBase):
  198. @staticmethod
  199. def get_registers_from_stack(data, grows_down):
  200. extra_regs = {v: 0 for v in XtensaRegisters().registers.values()}
  201. regs = [0] * REG_NUM
  202. # TODO: support for growing up stacks
  203. if not grows_down:
  204. raise ESPCoreDumpLoaderError('Growing up stacks are not supported for now!')
  205. ex_struct = Struct(
  206. 'stack' / Int32ul[XT_STK_FRMSZ]
  207. )
  208. if len(data) < ex_struct.sizeof():
  209. raise ESPCoreDumpLoaderError('Too small stack to keep frame: %d bytes!' % len(data))
  210. stack = ex_struct.parse(data).stack
  211. # Stack frame type indicator is always the first item
  212. rc = stack[XT_STK_EXIT]
  213. if rc != 0:
  214. regs[REG_PC_IDX] = stack[XT_STK_PC]
  215. regs[REG_PS_IDX] = stack[XT_STK_PS]
  216. for i in range(XT_STK_AR_NUM):
  217. regs[REG_AR_START_IDX + i] = stack[XT_STK_AR_START + i]
  218. regs[REG_SAR_IDX] = stack[XT_STK_SAR]
  219. regs[REG_LB_IDX] = stack[XT_STK_LBEG]
  220. regs[REG_LE_IDX] = stack[XT_STK_LEND]
  221. regs[REG_LC_IDX] = stack[XT_STK_LCOUNT]
  222. # FIXME: crashed and some running tasks (e.g. prvIdleTask) have EXCM bit set
  223. # and GDB can not unwind callstack properly (it implies not windowed call0)
  224. if regs[REG_PS_IDX] & (1 << 5):
  225. regs[REG_PS_IDX] &= ~(1 << 4)
  226. if stack[XT_STK_EXCCAUSE] in XTENSA_EXCEPTION_CAUSE_DICT:
  227. extra_regs[XtensaRegisters.EXCCAUSE_IDX] = stack[XT_STK_EXCCAUSE]
  228. else:
  229. extra_regs[XtensaRegisters.EXCCAUSE_IDX] = INVALID_CAUSE_VALUE
  230. extra_regs[XtensaRegisters.EXCVADDR_IDX] = stack[XT_STK_EXCVADDR]
  231. else:
  232. regs[REG_PC_IDX] = stack[XT_SOL_PC]
  233. regs[REG_PS_IDX] = stack[XT_SOL_PS]
  234. for i in range(XT_SOL_AR_NUM):
  235. regs[REG_AR_START_IDX + i] = stack[XT_SOL_AR_START + i]
  236. # nxt = stack[XT_SOL_NEXT]
  237. return regs, extra_regs
  238. @staticmethod
  239. def build_prstatus_data(tcb_addr, task_regs):
  240. return XtensaPrStatus.build({
  241. 'si_signo': 0,
  242. 'si_code': 0,
  243. 'si_errno': 0,
  244. 'pr_cursig': 0, # TODO: set sig only for current/failed task
  245. 'pr_pad0': 0,
  246. 'pr_sigpend': 0,
  247. 'pr_sighold': 0,
  248. 'pr_pid': tcb_addr,
  249. 'pr_ppid': 0,
  250. 'pr_pgrp': 0,
  251. 'pr_sid': 0,
  252. 'pr_utime': 0,
  253. 'pr_stime': 0,
  254. 'pr_cutime': 0,
  255. 'pr_cstime': 0,
  256. }) + Int32ul[len(task_regs)].build(task_regs)