pytest_panic.py 27 KB

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