pytest_panic.py 27 KB

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