pytest_panic.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: CC0-1.0
  3. import re
  4. from typing import List, Optional
  5. import pexpect
  6. import pytest
  7. from test_panic_util import PanicTestDut
  8. # Markers for all the targets this test currently runs on
  9. TARGETS_TESTED = [pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.esp32c3, pytest.mark.esp32s3, pytest.mark.esp32c2]
  10. # Most tests run on all targets and with all configs.
  11. # This list is passed to @pytest.mark.parametrize for each of the test cases.
  12. # It creates an outer product of the sets: [configs] x [targets],
  13. # with some exceptions.
  14. CONFIGS = [
  15. pytest.param('coredump_flash_bin_crc', marks=TARGETS_TESTED),
  16. pytest.param('coredump_flash_elf_sha', marks=[pytest.mark.esp32]), # sha256 only supported on esp32, IDF-1820
  17. pytest.param('coredump_uart_bin_crc', marks=TARGETS_TESTED),
  18. pytest.param('coredump_uart_elf_crc', marks=TARGETS_TESTED),
  19. pytest.param('gdbstub', marks=TARGETS_TESTED),
  20. pytest.param('panic', marks=TARGETS_TESTED),
  21. ]
  22. # Some tests only run on dual-core targets, they use the config below.
  23. TARGETS_DUAL_CORE = [pytest.mark.esp32, pytest.mark.esp32s3]
  24. CONFIGS_DUAL_CORE = [
  25. pytest.param('coredump_flash_bin_crc', marks=TARGETS_DUAL_CORE),
  26. pytest.param('coredump_flash_elf_sha', marks=[pytest.mark.esp32]), # sha256 only supported on esp32, IDF-1820
  27. pytest.param('coredump_uart_bin_crc', marks=TARGETS_DUAL_CORE),
  28. pytest.param('coredump_uart_elf_crc', marks=TARGETS_DUAL_CORE),
  29. pytest.param('gdbstub', marks=TARGETS_DUAL_CORE),
  30. pytest.param('panic', marks=TARGETS_DUAL_CORE),
  31. ]
  32. # Some tests run on all targets but need to behave differently on the dual-core ones.
  33. # This list is used to check if the target is a dual-core one.
  34. TARGETS_DUAL_CORE_NAMES = [x.mark.name for x in TARGETS_DUAL_CORE]
  35. # The tests which panic on external stack require PSRAM capable runners
  36. CONFIGS_EXTRAM_STACK = [
  37. pytest.param('coredump_extram_stack', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.psram, pytest.mark.esp32s3, pytest.mark.quad_psram])
  38. ]
  39. def get_default_backtrace(config: str) -> List[str]:
  40. return [config, 'app_main', 'main_task', 'vPortTaskWrapper']
  41. def common_test(dut: PanicTestDut, config: str, expected_backtrace: Optional[List[str]] = None) -> None:
  42. if 'gdbstub' in config:
  43. dut.expect_exact('Entering gdb stub now.')
  44. dut.start_gdb()
  45. frames = dut.gdb_backtrace()
  46. if expected_backtrace is not None:
  47. dut.verify_gdb_backtrace(frames, expected_backtrace)
  48. dut.revert_log_level()
  49. return # don't expect "Rebooting" output below
  50. if 'uart' in config:
  51. dut.process_coredump_uart()
  52. elif 'flash' in config:
  53. dut.process_coredump_flash()
  54. elif 'panic' in config:
  55. pass
  56. dut.expect('Rebooting...')
  57. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  58. @pytest.mark.generic
  59. def test_task_wdt_cpu0(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  60. dut.run_test_func(test_func_name)
  61. dut.expect_exact(
  62. 'Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:'
  63. )
  64. dut.expect_exact('CPU 0: main')
  65. if dut.is_xtensa:
  66. # on Xtensa, dumping registers on abort is not necessary, we only need to dump the backtrace
  67. dut.expect_none('register dump:')
  68. dut.expect_exact('Print CPU 0 (current core) backtrace')
  69. dut.expect_backtrace()
  70. else:
  71. # on RISC-V, need to dump both registers and stack memory to reconstruct the backtrace
  72. dut.expect_reg_dump(core=0)
  73. dut.expect_stack_dump()
  74. dut.expect_elf_sha256()
  75. dut.expect_none('Guru Meditation')
  76. common_test(
  77. dut,
  78. config,
  79. expected_backtrace=get_default_backtrace(test_func_name),
  80. )
  81. @pytest.mark.parametrize('config', CONFIGS_DUAL_CORE, indirect=True)
  82. @pytest.mark.generic
  83. def test_task_wdt_cpu1(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  84. dut.run_test_func(test_func_name)
  85. dut.expect_exact(
  86. 'Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:'
  87. )
  88. dut.expect_exact('CPU 1: Infinite loop')
  89. if dut.is_xtensa:
  90. # see comment in test_task_wdt_cpu0
  91. dut.expect_none('register dump:')
  92. dut.expect_exact('Print CPU 1 backtrace')
  93. dut.expect_backtrace()
  94. # On Xtensa, we get incorrect backtrace from GDB in this test
  95. expected_backtrace = ['infinite_loop', 'vPortTaskWrapper']
  96. else:
  97. assert False, 'No dual-core RISC-V chips yet, check this test case later'
  98. dut.expect_elf_sha256()
  99. dut.expect_none('Guru Meditation')
  100. common_test(
  101. dut,
  102. config,
  103. expected_backtrace=expected_backtrace,
  104. )
  105. @pytest.mark.parametrize('config', CONFIGS_DUAL_CORE, indirect=True)
  106. @pytest.mark.generic
  107. def test_task_wdt_both_cpus(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  108. if dut.target == 'esp32s3':
  109. pytest.xfail(reason='Only prints "Print CPU 1 backtrace", IDF-6560')
  110. dut.run_test_func(test_func_name)
  111. dut.expect_exact(
  112. 'Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:'
  113. )
  114. dut.expect_exact('CPU 0: Infinite loop')
  115. dut.expect_exact('CPU 1: Infinite loop')
  116. if dut.is_xtensa:
  117. # see comment in test_task_wdt_cpu0
  118. dut.expect_none('register dump:')
  119. dut.expect_exact('Print CPU 0 (current core) backtrace')
  120. dut.expect_backtrace()
  121. dut.expect_exact('Print CPU 1 backtrace')
  122. dut.expect_backtrace()
  123. # On Xtensa, we get incorrect backtrace from GDB in this test
  124. expected_backtrace = ['infinite_loop', 'vPortTaskWrapper']
  125. else:
  126. assert False, 'No dual-core RISC-V chips yet, check this test case later'
  127. dut.expect_elf_sha256()
  128. dut.expect_none('Guru Meditation')
  129. common_test(
  130. dut,
  131. config,
  132. expected_backtrace=expected_backtrace,
  133. )
  134. @pytest.mark.parametrize('config', CONFIGS_EXTRAM_STACK, indirect=True)
  135. def test_panic_extram_stack(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  136. dut.run_test_func(test_func_name)
  137. dut.expect_none('Allocated stack is not in external RAM')
  138. dut.expect_none('Guru Meditation')
  139. dut.expect_backtrace()
  140. dut.expect_elf_sha256()
  141. # Check that coredump is getting written to flash
  142. dut.expect_exact('Save core dump to flash...')
  143. # And that the stack is replaced and restored
  144. dut.expect_exact('Backing up stack @')
  145. dut.expect_exact('Restoring stack')
  146. # The caller must be accessible after restoring the stack
  147. dut.expect_exact('Core dump has been saved to flash.')
  148. common_test(dut, config)
  149. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  150. @pytest.mark.generic
  151. def test_int_wdt(
  152. dut: PanicTestDut, target: str, config: str, test_func_name: str
  153. ) -> None:
  154. dut.run_test_func(test_func_name)
  155. dut.expect_gme('Interrupt wdt timeout on CPU0')
  156. dut.expect_reg_dump(0)
  157. if dut.is_xtensa:
  158. dut.expect_backtrace()
  159. else:
  160. dut.expect_stack_dump()
  161. if target in TARGETS_DUAL_CORE_NAMES:
  162. assert dut.is_xtensa, 'No dual-core RISC-V chips yet, check the test case'
  163. dut.expect_reg_dump(1)
  164. dut.expect_backtrace()
  165. dut.expect_elf_sha256()
  166. dut.expect_none('Guru Meditation')
  167. common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
  168. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  169. @pytest.mark.generic
  170. def test_int_wdt_cache_disabled(
  171. dut: PanicTestDut, target: str, config: str, test_func_name: str
  172. ) -> None:
  173. dut.run_test_func(test_func_name)
  174. dut.expect_gme('Interrupt wdt timeout on CPU0')
  175. dut.expect_reg_dump(0)
  176. if dut.is_xtensa:
  177. dut.expect_backtrace()
  178. else:
  179. dut.expect_stack_dump()
  180. if target in TARGETS_DUAL_CORE_NAMES:
  181. assert dut.is_xtensa, 'No dual-core RISC-V chips yet, check the test case'
  182. dut.expect_reg_dump(1)
  183. dut.expect_backtrace()
  184. dut.expect_elf_sha256()
  185. dut.expect_none('Guru Meditation')
  186. common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
  187. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  188. @pytest.mark.generic
  189. def test_cache_error(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  190. dut.run_test_func(test_func_name)
  191. if dut.target in ['esp32c3', 'esp32c2']:
  192. # Cache error interrupt is not raised, IDF-6398
  193. dut.expect_gme('Illegal instruction')
  194. elif dut.target in ['esp32s2']:
  195. # Cache error interrupt is not enabled, IDF-1558
  196. dut.expect_gme('IllegalInstruction')
  197. else:
  198. dut.expect_gme('Cache disabled but cached memory region accessed')
  199. dut.expect_reg_dump(0)
  200. if dut.is_xtensa:
  201. dut.expect_backtrace()
  202. else:
  203. dut.expect_stack_dump()
  204. dut.expect_elf_sha256()
  205. dut.expect_none('Guru Meditation')
  206. expected_backtrace = ['die'] + get_default_backtrace(test_func_name)
  207. if dut.target in ['esp32s2', 'esp32s3']:
  208. # 'test_cache_error' missing from GDB backtrace on ESP32-S2 and ESP-S3, IDF-6561
  209. expected_backtrace = ['die', 'app_main', 'main_task', 'vPortTaskWrapper']
  210. common_test(
  211. dut, config, expected_backtrace=expected_backtrace
  212. )
  213. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  214. @pytest.mark.generic
  215. def test_stack_overflow(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  216. dut.run_test_func(test_func_name)
  217. if dut.is_xtensa:
  218. dut.expect_gme('Unhandled debug exception')
  219. dut.expect_exact('Stack canary watchpoint triggered (main)')
  220. else:
  221. # Stack watchpoint handling missing on RISC-V, IDF-6397
  222. dut.expect_gme('Breakpoint')
  223. dut.expect_reg_dump(0)
  224. if dut.is_xtensa:
  225. dut.expect_backtrace()
  226. else:
  227. dut.expect_stack_dump()
  228. dut.expect_elf_sha256()
  229. dut.expect_none('Guru Meditation')
  230. common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
  231. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  232. @pytest.mark.generic
  233. def test_instr_fetch_prohibited(
  234. dut: PanicTestDut, config: str, test_func_name: str
  235. ) -> None:
  236. dut.run_test_func(test_func_name)
  237. if dut.is_xtensa:
  238. dut.expect_gme('InstrFetchProhibited')
  239. dut.expect_reg_dump(0)
  240. dut.expect_backtrace()
  241. expected_backtrace = ['_init'] + get_default_backtrace(test_func_name)
  242. else:
  243. dut.expect_gme('Instruction access fault')
  244. dut.expect_reg_dump(0)
  245. dut.expect_stack_dump()
  246. # On RISC-V, GDB is not able to determine the correct backtrace after
  247. # a jump to an invalid address.
  248. expected_backtrace = ['??']
  249. dut.expect_elf_sha256()
  250. dut.expect_none('Guru Meditation')
  251. common_test(
  252. dut,
  253. config,
  254. expected_backtrace=expected_backtrace,
  255. )
  256. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  257. @pytest.mark.generic
  258. def test_illegal_instruction(
  259. dut: PanicTestDut, config: str, test_func_name: str
  260. ) -> None:
  261. dut.run_test_func(test_func_name)
  262. if dut.is_xtensa:
  263. dut.expect_gme('IllegalInstruction')
  264. else:
  265. dut.expect_gme('Illegal instruction')
  266. dut.expect_reg_dump(0)
  267. if dut.is_xtensa:
  268. dut.expect_backtrace()
  269. else:
  270. dut.expect_stack_dump()
  271. dut.expect_elf_sha256()
  272. dut.expect_none('Guru Meditation')
  273. common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
  274. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  275. @pytest.mark.generic
  276. def test_storeprohibited(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  277. dut.run_test_func(test_func_name)
  278. if dut.is_xtensa:
  279. dut.expect_gme('StoreProhibited')
  280. else:
  281. dut.expect_gme('Store access fault')
  282. dut.expect_reg_dump(0)
  283. if dut.is_xtensa:
  284. dut.expect_backtrace()
  285. else:
  286. dut.expect_stack_dump()
  287. dut.expect_elf_sha256()
  288. dut.expect_none('Guru Meditation')
  289. common_test(dut, config, expected_backtrace=get_default_backtrace(test_func_name))
  290. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  291. @pytest.mark.generic
  292. def test_abort(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  293. dut.run_test_func(test_func_name)
  294. dut.expect(r'abort\(\) was called at PC [0-9xa-f]+ on core 0')
  295. if dut.is_xtensa:
  296. dut.expect_backtrace()
  297. else:
  298. dut.expect_stack_dump()
  299. dut.expect_elf_sha256()
  300. dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
  301. common_test(
  302. dut,
  303. config,
  304. expected_backtrace=[
  305. 'panic_abort',
  306. 'esp_system_abort',
  307. 'abort'
  308. ] + get_default_backtrace(test_func_name),
  309. )
  310. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  311. @pytest.mark.generic
  312. def test_ub(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  313. dut.run_test_func(test_func_name)
  314. dut.expect('Undefined behavior of type out_of_bounds')
  315. if dut.is_xtensa:
  316. dut.expect_backtrace()
  317. else:
  318. dut.expect_stack_dump()
  319. dut.expect_elf_sha256()
  320. dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
  321. common_test(
  322. dut,
  323. config,
  324. expected_backtrace=[
  325. 'panic_abort',
  326. 'esp_system_abort',
  327. '__ubsan_default_handler',
  328. '__ubsan_handle_out_of_bounds'
  329. ] + get_default_backtrace(test_func_name),
  330. )
  331. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  332. @pytest.mark.generic
  333. def test_abort_cache_disabled(
  334. dut: PanicTestDut, config: str, test_func_name: str
  335. ) -> None:
  336. if dut.target == 'esp32s2':
  337. pytest.xfail(reason='Crashes in itoa which is not in ROM, IDF-3572')
  338. dut.run_test_func(test_func_name)
  339. dut.expect(r'abort\(\) was called at PC [0-9xa-f]+ on core 0')
  340. if dut.is_xtensa:
  341. dut.expect_backtrace()
  342. else:
  343. dut.expect_stack_dump()
  344. dut.expect_elf_sha256()
  345. dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
  346. common_test(
  347. dut,
  348. config,
  349. expected_backtrace=[
  350. 'panic_abort',
  351. 'esp_system_abort',
  352. 'abort'
  353. ] + get_default_backtrace(test_func_name),
  354. )
  355. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  356. @pytest.mark.generic
  357. def test_assert(dut: PanicTestDut, config: str, test_func_name: str) -> None:
  358. dut.run_test_func(test_func_name)
  359. dut.expect(
  360. re.compile(
  361. rb'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$', re.MULTILINE
  362. )
  363. )
  364. if dut.is_xtensa:
  365. dut.expect_backtrace()
  366. else:
  367. dut.expect_stack_dump()
  368. dut.expect_elf_sha256()
  369. dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
  370. common_test(
  371. dut,
  372. config,
  373. expected_backtrace=[
  374. 'panic_abort',
  375. 'esp_system_abort',
  376. '__assert_func'
  377. ] + get_default_backtrace(test_func_name))
  378. @pytest.mark.parametrize('config', CONFIGS, indirect=True)
  379. @pytest.mark.generic
  380. def test_assert_cache_disabled(
  381. dut: PanicTestDut, config: str, test_func_name: str
  382. ) -> None:
  383. if dut.target == 'esp32s2':
  384. pytest.xfail(reason='Crashes in itoa which is not in ROM, IDF-3572')
  385. dut.run_test_func(test_func_name)
  386. dut.expect(re.compile(rb'assert failed: [0-9xa-fA-F]+.*$', re.MULTILINE))
  387. if dut.is_xtensa:
  388. dut.expect_backtrace()
  389. else:
  390. dut.expect_stack_dump()
  391. dut.expect_elf_sha256()
  392. dut.expect_none(['Guru Meditation', 'Re-entered core dump'])
  393. common_test(
  394. dut,
  395. config,
  396. expected_backtrace=[
  397. 'panic_abort',
  398. 'esp_system_abort',
  399. '__assert_func'
  400. ] + get_default_backtrace(test_func_name))
  401. @pytest.mark.esp32
  402. @pytest.mark.parametrize('config', ['panic_delay'], indirect=True)
  403. def test_panic_delay(dut: PanicTestDut) -> None:
  404. dut.run_test_func('test_storeprohibited')
  405. try:
  406. dut.expect_exact('Rebooting...', timeout=4)
  407. except pexpect.TIMEOUT:
  408. # We are supposed to NOT find the output for the specified time
  409. pass
  410. else:
  411. # If we actually match the output within the timeout, it means the delay didn't work
  412. raise AssertionError('Rebooted too early, delay is too short')
  413. dut.expect_exact('Rebooting...', timeout=3)
  414. dut.expect_exact('rst:0xc (SW_CPU_RESET)')
  415. #########################
  416. # for memprot test only #
  417. #########################
  418. # Memprot-related tests are supported only on targets with PMS/PMA peripheral;
  419. # currently ESP32-S2, ESP32-C3 and ESP32-C2 are supported
  420. CONFIGS_MEMPROT_IDRAM = [
  421. pytest.param('memprot_esp32s2', marks=[pytest.mark.esp32s2]),
  422. pytest.param('memprot_esp32c3', marks=[pytest.mark.esp32c3]),
  423. pytest.param('memprot_esp32c2', marks=[pytest.mark.esp32c2])
  424. ]
  425. CONFIGS_MEMPROT_DCACHE = [
  426. pytest.param('memprot_esp32s2', marks=pytest.mark.esp32s2),
  427. ]
  428. CONFIGS_MEMPROT_RTC_FAST_MEM = [
  429. pytest.param('memprot_esp32s2', marks=[pytest.mark.esp32s2]),
  430. pytest.param('memprot_esp32c3', marks=[pytest.mark.esp32c3]),
  431. ]
  432. CONFIGS_MEMPROT_RTC_SLOW_MEM = [
  433. pytest.param('memprot_esp32s2', marks=[pytest.mark.esp32s2]),
  434. ]
  435. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_DCACHE, indirect=True)
  436. @pytest.mark.generic
  437. def test_dcache_read_violation(dut: PanicTestDut, test_func_name: str) -> None:
  438. dut.run_test_func(test_func_name)
  439. dut.expect_exact(r'Test error: Test function has returned')
  440. # TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs
  441. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_DCACHE, indirect=True)
  442. @pytest.mark.generic
  443. @pytest.mark.xfail('config.getvalue("target") == "esp32s2"', reason='Incorrect panic reason may be observed', run=False)
  444. def test_dcache_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
  445. dut.run_test_func(test_func_name)
  446. dut.expect_gme('Memory protection fault')
  447. dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  448. dut.expect_reg_dump(0)
  449. dut.expect_backtrace()
  450. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_IDRAM, indirect=True)
  451. @pytest.mark.generic
  452. def test_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
  453. dut.run_test_func(test_func_name)
  454. if dut.target == 'esp32s2':
  455. dut.expect_gme('Memory protection fault')
  456. dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  457. dut.expect_reg_dump(0)
  458. dut.expect_backtrace()
  459. elif dut.target == 'esp32c3':
  460. dut.expect_exact(r'Test error: Test function has returned')
  461. elif dut.target == 'esp32c2':
  462. dut.expect_gme('Store access fault')
  463. dut.expect_reg_dump(0)
  464. dut.expect_stack_dump()
  465. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_IDRAM, indirect=True)
  466. @pytest.mark.generic
  467. def test_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
  468. dut.run_test_func(test_func_name)
  469. if dut.target == 'esp32s2':
  470. dut.expect_gme('Memory protection fault')
  471. dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  472. dut.expect_reg_dump(0)
  473. dut.expect_backtrace()
  474. elif dut.target == 'esp32c3':
  475. dut.expect_gme('Memory protection fault')
  476. dut.expect(r' memory type: (\S+)')
  477. dut.expect(r' faulting address: [0-9xa-f]+')
  478. dut.expect(r' operation type: (\S+)')
  479. dut.expect_reg_dump(0)
  480. dut.expect_stack_dump()
  481. elif dut.target == 'esp32c2':
  482. dut.expect_gme('Store access fault')
  483. dut.expect_reg_dump(0)
  484. dut.expect_stack_dump()
  485. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_IDRAM, indirect=True)
  486. @pytest.mark.generic
  487. def test_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
  488. dut.run_test_func(test_func_name)
  489. if dut.target == 'esp32s2':
  490. dut.expect_gme('Memory protection fault')
  491. dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  492. dut.expect_reg_dump(0)
  493. dut.expect_backtrace()
  494. elif dut.target == 'esp32c3':
  495. dut.expect_gme('Memory protection fault')
  496. dut.expect(r' memory type: (\S+)')
  497. dut.expect(r' faulting address: [0-9xa-f]+')
  498. dut.expect(r' operation type: (\S+)')
  499. dut.expect_reg_dump(0)
  500. dut.expect_stack_dump()
  501. elif dut.target == 'esp32c2':
  502. dut.expect_gme('Store access fault')
  503. dut.expect_reg_dump(0)
  504. dut.expect_stack_dump()
  505. # TODO: IDF-6820: ESP32-S2 -> Fix incorrect panic reason: Unhandled debug exception
  506. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_IDRAM, indirect=True)
  507. @pytest.mark.generic
  508. @pytest.mark.xfail('config.getvalue("target") == "esp32s2"', reason='Incorrect panic reason may be observed', run=False)
  509. def test_iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
  510. dut.run_test_func(test_func_name)
  511. if dut.target == 'esp32s2':
  512. dut.expect_gme('Memory protection fault')
  513. dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  514. dut.expect_reg_dump(0)
  515. dut.expect_backtrace()
  516. elif dut.target == 'esp32c3':
  517. dut.expect_gme('Memory protection fault')
  518. dut.expect(r' memory type: (\S+)')
  519. dut.expect(r' faulting address: [0-9xa-f]+')
  520. dut.expect(r' operation type: (\S+)')
  521. dut.expect_reg_dump(0)
  522. dut.expect_stack_dump()
  523. elif dut.target == 'esp32c2':
  524. dut.expect_gme('Store access fault')
  525. dut.expect_reg_dump(0)
  526. dut.expect_stack_dump()
  527. # TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs
  528. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_IDRAM, indirect=True)
  529. @pytest.mark.generic
  530. @pytest.mark.xfail('config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False)
  531. def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
  532. dut.run_test_func(test_func_name)
  533. if dut.target == 'esp32s2':
  534. dut.expect_gme('Memory protection fault')
  535. dut.expect(r'Unknown operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  536. dut.expect_reg_dump(0)
  537. dut.expect_corrupted_backtrace()
  538. elif dut.target in ['esp32c3', 'esp32c2']:
  539. dut.expect_gme('Instruction access fault')
  540. dut.expect_reg_dump(0)
  541. dut.expect_stack_dump()
  542. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_IDRAM, indirect=True)
  543. @pytest.mark.generic
  544. def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
  545. dut.run_test_func(test_func_name)
  546. if dut.target == 'esp32s2':
  547. dut.expect_gme('InstructionFetchError')
  548. dut.expect_reg_dump(0)
  549. dut.expect_corrupted_backtrace()
  550. elif dut.target in ['esp32c3', 'esp32c2']:
  551. dut.expect_gme('Instruction access fault')
  552. dut.expect_reg_dump(0)
  553. dut.expect_stack_dump()
  554. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=True)
  555. @pytest.mark.generic
  556. def test_rtc_fast_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
  557. dut.run_test_func(test_func_name)
  558. dut.expect_exact(r'Test error: Test function has returned')
  559. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=True)
  560. @pytest.mark.generic
  561. def test_rtc_fast_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
  562. dut.run_test_func(test_func_name)
  563. dut.expect_gme('Memory protection fault')
  564. if dut.target == 'esp32s2':
  565. dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  566. dut.expect_reg_dump(0)
  567. dut.expect_backtrace()
  568. elif dut.target == 'esp32c3':
  569. dut.expect(r' memory type: (\S+)')
  570. dut.expect(r' faulting address: [0-9xa-f]+')
  571. dut.expect(r' operation type: (\S+)')
  572. dut.expect_reg_dump(0)
  573. dut.expect_stack_dump()
  574. # TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs
  575. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=True)
  576. @pytest.mark.generic
  577. @pytest.mark.xfail('config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False)
  578. def test_rtc_fast_reg3_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
  579. dut.run_test_func(test_func_name)
  580. dut.expect_gme('Memory protection fault')
  581. if dut.target == 'esp32s2':
  582. dut.expect(r'Unknown operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  583. dut.expect_reg_dump(0)
  584. dut.expect_backtrace()
  585. elif dut.target == 'esp32c3':
  586. dut.expect(r' memory type: (\S+)')
  587. dut.expect(r' faulting address: [0-9xa-f]+')
  588. dut.expect(r' operation type: (\S+)')
  589. dut.expect_reg_dump(0)
  590. dut.expect_stack_dump()
  591. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_RTC_SLOW_MEM, indirect=True)
  592. @pytest.mark.generic
  593. def test_rtc_slow_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
  594. dut.run_test_func(test_func_name)
  595. dut.expect_gme('Memory protection fault')
  596. dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  597. dut.expect_reg_dump(0)
  598. dut.expect_corrupted_backtrace()
  599. @pytest.mark.parametrize('config', CONFIGS_MEMPROT_RTC_SLOW_MEM, indirect=True)
  600. @pytest.mark.generic
  601. def test_rtc_slow_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
  602. dut.run_test_func(test_func_name)
  603. dut.expect_gme('Memory protection fault')
  604. dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)')
  605. dut.expect_reg_dump(0)
  606. dut.expect_corrupted_backtrace()
  607. @pytest.mark.esp32
  608. @pytest.mark.parametrize('config', ['gdbstub_coredump'], indirect=True)
  609. def test_gdbstub_coredump(dut: PanicTestDut) -> None:
  610. test_func_name = 'test_storeprohibited'
  611. dut.run_test_func(test_func_name)
  612. dut.process_coredump_uart()
  613. dut.expect_exact('Entering gdb stub now.')
  614. dut.start_gdb()
  615. frames = dut.gdb_backtrace()
  616. dut.verify_gdb_backtrace(frames, get_default_backtrace(test_func_name))
  617. dut.revert_log_level()
  618. return # don't expect "Rebooting" output below