pytest_runtime.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: CC0-1.0
  3. import os.path as path
  4. import sys
  5. import pytest
  6. sys.path.append(path.expandvars(path.join('$IDF_PATH', 'tools', 'test_apps', 'system', 'panic')))
  7. from test_panic_util import PanicTestDut # noqa: E402
  8. def get_line_number(lookup: str, offset: int = 0) -> int:
  9. src_file = path.join(path.dirname(path.abspath(__file__)), 'main', 'test_app_main.c')
  10. with open(src_file) as f:
  11. for num, line in enumerate(f, 1):
  12. if lookup in line:
  13. return num + offset
  14. return -1
  15. @pytest.mark.supported_targets
  16. @pytest.mark.generic
  17. def test_gdbstub_runtime(dut: PanicTestDut) -> None:
  18. dut.expect_exact('tested app is runnig.')
  19. dut.write(b'\x03') # send Ctrl-C
  20. dut.start_gdb()
  21. # Test breakpoint
  22. cmd = '-break-insert --source test_app_main.c --function app_main --label label_1'
  23. response = dut.find_gdb_response('done', 'result', dut.gdb_write(cmd))
  24. assert response is not None
  25. cmd = '-exec-continue'
  26. responses = dut.gdb_write(cmd)
  27. assert dut.find_gdb_response('running', 'result', responses) is not None
  28. if not dut.find_gdb_response('stopped', 'notify', responses):
  29. # have not stopped on breakpoint yet
  30. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  31. assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  32. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  33. assert payload['reason'] == 'breakpoint-hit'
  34. assert payload['bkptno'] == '1'
  35. assert payload['frame']['func'] == 'app_main'
  36. assert payload['frame']['line'] == str(get_line_number('label_1:', 1))
  37. assert payload['stopped-threads'] == 'all'
  38. # Test step command
  39. cmd = '-exec-step'
  40. responses = dut.gdb_write(cmd)
  41. assert dut.find_gdb_response('running', 'result', responses) is not None
  42. if not dut.find_gdb_response('stopped', 'notify', responses):
  43. # have not stopped on breakpoint yet
  44. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  45. assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  46. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  47. assert payload['reason'] == 'end-stepping-range'
  48. assert payload['frame']['func'] == 'foo'
  49. assert payload['frame']['line'] == str(get_line_number('var_2+=2;'))
  50. assert payload['stopped-threads'] == 'all'
  51. # Test finish command
  52. cmd = '-exec-finish'
  53. responses = dut.gdb_write(cmd)
  54. assert dut.find_gdb_response('running', 'result', responses) is not None
  55. if not dut.find_gdb_response('stopped', 'notify', responses):
  56. # have not stopped on breakpoint yet
  57. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  58. assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  59. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  60. assert payload['reason'] == 'function-finished'
  61. # On riscv we may have situation when returned from a function but stay on exactly the same line
  62. # foo();
  63. # 4200ae5c: f99ff0ef jal ra,4200adf4 <foo>
  64. # 4200ae60: a011 j 4200ae64 <app_main+0x4e> <----------- here after return from foo()
  65. # }
  66. assert payload['frame']['line'] == str(get_line_number('label_3:', 1) if dut.is_xtensa else get_line_number('foo();', 0))
  67. assert payload['frame']['func'] == 'app_main'
  68. assert payload['stopped-threads'] == 'all'
  69. cmd = '-exec-continue'
  70. responses = dut.gdb_write(cmd)
  71. assert dut.find_gdb_response('running', 'result', responses) is not None
  72. assert dut.find_gdb_response('running', 'notify', responses) is not None
  73. # Test next command
  74. cmd = '-exec-next'
  75. responses = dut.gdb_write(cmd)
  76. assert dut.find_gdb_response('running', 'result', responses) is not None
  77. if not dut.find_gdb_response('stopped', 'notify', responses):
  78. # have not stopped on breakpoint yet
  79. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  80. assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  81. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  82. assert payload['reason'] == 'end-stepping-range'
  83. assert payload['frame']['line'] == str(get_line_number('label_3:', 1))
  84. assert payload['frame']['func'] == 'app_main'
  85. assert payload['stopped-threads'] == 'all'
  86. # test delete breakpoint
  87. cmd = '-break-delete 1'
  88. responses = dut.gdb_write(cmd)
  89. assert dut.find_gdb_response('done', 'result', responses) is not None
  90. cmd = '-exec-continue'
  91. responses = dut.gdb_write(cmd)
  92. assert dut.find_gdb_response('running', 'result', responses) is not None
  93. assert dut.find_gdb_response('running', 'notify', responses) is not None
  94. # test ctrl-c
  95. responses = dut.gdbmi.send_signal_to_gdb(2)
  96. # assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  97. # ?? No response? check we stopped
  98. dut.gdb_backtrace()
  99. # test watchpoint
  100. cmd = '-break-watch var_2'
  101. responses = dut.gdb_write(cmd)
  102. assert dut.find_gdb_response('done', 'result', responses) is not None
  103. cmd = '-exec-continue'
  104. responses = dut.gdb_write(cmd)
  105. assert dut.find_gdb_response('running', 'result', responses) is not None
  106. if not dut.find_gdb_response('stopped', 'notify', responses):
  107. # have not stopped on breakpoint yet
  108. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  109. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  110. assert payload['reason'] == 'signal-received'
  111. assert payload['frame']['func'] == 'foo'
  112. assert payload['stopped-threads'] == 'all'
  113. # Uncomment this when implement send reason to gdb: GCC-313
  114. #
  115. # assert payload['reason'] == 'watchpoint-trigger'
  116. # assert int(payload['value']['new']) == int(payload['value']['old']) + 1
  117. # assert payload['frame']['line'] == '14'
  118. cmd = '-break-delete 2'
  119. responses = dut.gdb_write(cmd)
  120. assert dut.find_gdb_response('done', 'result', responses) is not None
  121. # test set variable
  122. cmd = '-gdb-set do_panic=1'
  123. responses = dut.gdb_write(cmd)
  124. assert dut.find_gdb_response('done', 'result', responses) is not None
  125. # test panic handling
  126. cmd = '-exec-continue'
  127. responses = dut.gdb_write(cmd)
  128. assert dut.find_gdb_response('running', 'result', responses) is not None
  129. if not dut.find_gdb_response('stopped', 'notify', responses):
  130. # have not stopped on breakpoint yet
  131. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  132. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  133. assert payload['reason'] == 'signal-received'
  134. assert payload['signal-name'] == 'SIGSEGV'
  135. assert payload['frame']['func'] == 'app_main'
  136. assert payload['frame']['line'] == str(get_line_number('label_5', 1))
  137. assert payload['stopped-threads'] == 'all'
  138. @pytest.mark.esp32
  139. @pytest.mark.esp32s2
  140. @pytest.mark.esp32s3
  141. @pytest.mark.generic
  142. @pytest.mark.temp_skip_ci(targets=['esp32', 'esp32s2', 'esp32s3'], reason='fix IDF-7927')
  143. def test_gdbstub_runtime_xtensa_stepping_bug(dut: PanicTestDut) -> None:
  144. dut.expect_exact('tested app is runnig.')
  145. dut.write(b'\x03') # send Ctrl-C
  146. dut.start_gdb()
  147. # Test breakpoint
  148. cmd = '-break-insert --source test_app_main.c --function app_main --label label_1'
  149. response = dut.find_gdb_response('done', 'result', dut.gdb_write(cmd))
  150. assert response is not None
  151. cmd = '-exec-continue'
  152. responses = dut.gdb_write(cmd)
  153. assert dut.find_gdb_response('running', 'result', responses) is not None
  154. if not dut.find_gdb_response('stopped', 'notify', responses):
  155. # have not stopped on breakpoint yet
  156. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  157. assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  158. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  159. assert payload['reason'] == 'breakpoint-hit'
  160. assert payload['bkptno'] == '1'
  161. assert payload['frame']['func'] == 'app_main'
  162. assert payload['frame']['line'] == str(get_line_number('label_1:', 1))
  163. assert payload['stopped-threads'] == 'all'
  164. # Test step command
  165. cmd = '-exec-step'
  166. responses = dut.gdb_write(cmd)
  167. assert dut.find_gdb_response('running', 'result', responses) is not None
  168. if not dut.find_gdb_response('stopped', 'notify', responses):
  169. # have not stopped on breakpoint yet
  170. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  171. assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  172. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  173. assert payload['reason'] == 'end-stepping-range'
  174. assert payload['frame']['func'] == 'foo'
  175. assert payload['frame']['line'] == str(get_line_number('var_2+=2;'))
  176. assert payload['stopped-threads'] == 'all'
  177. # Test next command
  178. cmd = '-exec-next'
  179. responses = dut.gdb_write(cmd)
  180. assert dut.find_gdb_response('running', 'result', responses) is not None
  181. if not dut.find_gdb_response('stopped', 'notify', responses):
  182. # have not stopped on breakpoint yet
  183. responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
  184. assert dut.find_gdb_response('stopped', 'notify', responses) is not None
  185. payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
  186. assert payload['reason'] == 'end-stepping-range'
  187. assert payload['frame']['line'] == str(get_line_number('var_2--;', 0))
  188. assert payload['frame']['func'] == 'foo'
  189. assert payload['stopped-threads'] == 'all'