From: Evgeniy Temirgaleev via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: "Sergey Kaplun" <skaplun@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: Re: [Tarantool-patches] [PATCH v2 luajit 1/6] test: introduce tests for debugging extensions
Date: Tue, 26 May 2026 16:50:27 +0300 [thread overview]
Message-ID: <1779803427.60260456@f511.i.mail.ru> (raw)
In-Reply-To: <20260519123913.178775-2-skaplun@tarantool.org>
[-- Attachment #1: Type: text/plain, Size: 14582 bytes --]
Hi, Sergey!
Thanks for the patch. Please, consider my suggestion: the debugger-aware «constants» are defined in one block per debugger.
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 30a2c478..f4414f4d 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -19,9 +19,6 @@ LLDB = 'lldb' in DEBUGGER
EXTENSION = EXTENSION_PATH + '/luajit_dbg.py'
TIMEOUT = 10
-# Don't run any initialization scripts.
-RUN_CMD_FILE = []
-
if LLDB:
RUN_CMD_FILE = [
'--batch',
@@ -30,15 +27,15 @@ if LLDB:
'--source-quietly',
'--source'
]
+ INFERIOR_ARGS = '--'
+ PROCESS_RUN = 'process launch'
+ LOAD_EXTENSION = 'command script import {ext}'.format(ext=EXTENSION)
else:
# GDB.
RUN_CMD_FILE = ['--batch', '--nx', '--quiet', '--command']
-
-INFERIOR_ARGS = '--' if LLDB else '--args'
-PROCESS_RUN = 'process launch' if LLDB else 'r'
-LOAD_EXTENSION = (
- 'command script import {ext}' if LLDB else 'source {ext}'
-).format(ext=EXTENSION)
+ INFERIOR_ARGS = '--args'
+ PROCESS_RUN = 'r'
+ LOAD_EXTENSION = 'source {ext}'.format(ext=EXTENSION)
--
Best regards,
Evgeniy Temirgaleev
>
> From: Sergey Kaplun <skaplun@tarantool.org>
> To: Mikhail Elhimov <m.elhimov@vk.team>, Sergey Bronnikov <sergeyb@tarantool.org
> >, Evgeniy Temirgaleev <e.temirgaleev@tarantool.org>
> Cc: tarantool-patches@dev.tarantool.org, Sergey Kaplun <skaplun@tarantool.org
> >
> Date: Tuesday, May 19, 2026 3:40 PM +03:00
> From: Maxim Kokryashkin <m.kokryashkin@tarantool.org>
>
> This patch adds tests for LuaJIT debugging extensions for lldb and gdb.
> The tests are written in Python's unittest framework [1].
>
> Most of the tests are failed for the lldb due to outdated extension
> sources and overcomplicated hard-coded C structures fields
> introspection. Hence, tests for LLDB are disabled since they are failing
> anyway.
>
> The tarantool-debugger-tests target is introduced. This target is
> included in the LuaJIT-check-all target but not in the LuaJIT-test
> target to avoid it running for all LuaJIT builds by default in CI.
>
> [1]: https://docs.python.org/3/library/unittest.html
> ---
> test/CMakeLists.txt | 7 +
> test/tarantool-debugger-tests/CMakeLists.txt | 93 ++++++
> .../debug-extension-tests.py | 286 ++++++++++++++++++
> 3 files changed, 386 insertions(+)
> create mode 100644 test/tarantool-debugger-tests/CMakeLists.txt
> create mode 100644 test/tarantool-debugger-tests/debug-extension-tests.py
>
> diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
> index f48afa25..26b15892 100644
> --- a/test/CMakeLists.txt
> +++ b/test/CMakeLists.txt
> @@ -175,6 +175,7 @@ add_subdirectory(LuaJIT-tests)
> add_subdirectory(PUC-Rio-Lua-5.1-tests)
> add_subdirectory(lua-Harness-tests)
> add_subdirectory(tarantool-c-tests)
> +add_subdirectory(tarantool-debugger-tests)
> add_subdirectory(tarantool-tests)
>
> # Each testsuite has its own CMake target, but combining these
> @@ -186,6 +187,9 @@ add_subdirectory(tarantool-tests)
> # command that runs all generated CMake tests.
> add_custom_target(${PROJECT_NAME}-test
> COMMAND ${CMAKE_CTEST_COMMAND} ${CTEST_FLAGS}
> + # Omit this target in LuaJIT-test since we don't want to set
> + # up and run debuggers for every build.
> + --label-exclude tarantool-debugger-tests
> DEPENDS tarantool-c-tests-deps
> tarantool-tests-deps
> lua-Harness-tests-deps
> @@ -195,5 +199,8 @@ add_custom_target(${PROJECT_NAME}-test
>
> add_custom_target(${PROJECT_NAME}-check-all
> DEPENDS ${PROJECT_NAME}-test
> + # Omit this target in LuaJIT-test since we don't want to
> + # set up and run debuggers for every build.
> + tarantool-debugger-tests
> ${PROJECT_NAME}-lint
> )
> diff --git a/test/tarantool-debugger-tests/CMakeLists.txt
> b/test/tarantool-debugger-tests/CMakeLists.txt
> new file mode 100644
> index 00000000..7fd0debc
> --- /dev/null
> +++ b/test/tarantool-debugger-tests/CMakeLists.txt
> @@ -0,0 +1,93 @@
> +set(TEST_SUITE_NAME "tarantool-debugger-tests")
> +
> +# XXX: The call produces both test and target
> +# <tarantool-debugger-tests-deps> as a side effect.
> +add_test_suite_target(tarantool-debugger-tests
> + LABELS ${TEST_SUITE_NAME}
> + DEPENDS ${LUAJIT_TEST_BINARY}
> +)
> +
> +# Debug info is required for testing of extensions.
> +if(NOT (CMAKE_BUILD_TYPE MATCHES Debug))
> + message(WARNING
> + "Not a DEBUG build, tarantool-debugger-tests is dummy"
> + )
> + return()
> +endif()
> +
> +# MacOS asks for permission to debug a process even when the
> +# machine is set into development mode. To solve the issue,
> +# it is required to add relevant users to the `_developer` user
> +# group in macOS. Disabled for now.
> +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND DEFINED ENV{CI})
> + message(WARNING
> + "Interactive debugging is unavailable for macOS CI builds,"
> + " tarantool-debugger-tests is dummy"
> + )
> + return()
> +endif()
> +
> +if(CMAKE_VERSION VERSION_LESS "3.12")
> + # TODO:Can remove this after upgrading to CMake >= 3.12.
> + find_package(PythonInterp)
> + if(NOT PYTHONINTERP_FOUND)
> + message(WARNING "`python` is not found, tarantool-debugger-tests is
> dummy")
> + return()
> + endif()
> +else()
> + find_package(Python COMPONENTS Interpreter)
> + if(NOT PYTHON_FOUND)
> + message(WARNING "`python` is not found, tarantool-debugger-tests is
> dummy")
> + return()
> + endif()
> + set(PYTHON_EXECUTABLE "${Python_EXECUTABLE}")
> +endif()
> +
> +set(DEBUGGER_TEST_ENV
> + "LUAJIT_TEST_BINARY=${LUAJIT_TEST_BINARY}"
> + # Suppresses __pycache__ generation.
> + "PYTHONDONTWRITEBYTECODE=1"
> + "DEBUGGER_EXTENSION_PATH=${PROJECT_SOURCE_DIR}/src"
> +)
> +
> +set(TEST_SCRIPT_PATH
> + ${CMAKE_CURRENT_SOURCE_DIR}/debug-extension-tests.py
> +)
> +
> +find_program(GDB gdb)
> +if(GDB)
> + set(test_title "test/${TEST_SUITE_NAME}/gdb")
> + set(GDB_TEST_ENV ${DEBUGGER_TEST_ENV} "DEBUGGER_COMMAND=${GDB}")
> + add_test(NAME "${test_title}"
> + COMMAND ${PYTHON_EXECUTABLE} ${TEST_SCRIPT_PATH}
> + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
> + )
> + set_tests_properties("${test_title}" PROPERTIES
> + ENVIRONMENT "${GDB_TEST_ENV}"
> + LABELS ${TEST_SUITE_NAME}
> + DEPENDS tarantool-debugger-tests-deps
> + )
> +else()
> + message(WARNING
> + "`gdb' is not found, so tarantool-debugger-tests/gdb is omitted"
> + )
> +endif()
> +
> +find_program(LLDB lldb)
> +if(LLDB)
> + set(test_title "test/${TEST_SUITE_NAME}/lldb")
> + set(LLDB_TEST_ENV ${DEBUGGER_TEST_ENV} "DEBUGGER_COMMAND=${LLDB}")
> + add_test(NAME "${test_title}"
> + COMMAND ${PYTHON_EXECUTABLE} ${TEST_SCRIPT_PATH}
> + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
> + )
> + set_tests_properties("${test_title}" PROPERTIES
> + ENVIRONMENT "${LLDB_TEST_ENV}"
> + LABELS ${TEST_SUITE_NAME}
> + DEPENDS tarantool-debugger-tests-deps
> + )
> +else()
> + message(WARNING
> + "`lldb' is not found, so tarantool-debugger-tests/lldb is omitted"
> + )
> +endif()
> diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py
> b/test/tarantool-debugger-tests/debug-extension-tests.py
> new file mode 100644
> index 00000000..6094c535
> --- /dev/null
> +++ b/test/tarantool-debugger-tests/debug-extension-tests.py
> @@ -0,0 +1,286 @@
> +# This file provides tests for LuaJIT debug extensions for lldb
> +# and gdb.
> +
> +import os
> +import re
> +import subprocess
> +import sys
> +import tempfile
> +import unittest
> +
> +from threading import Timer
> +
> +LEGACY = re.match(r'^2\.', sys.version)
> +
> +LUAJIT_BINARY = os.environ['LUAJIT_TEST_BINARY']
> +EXTENSION_PATH = os.environ['DEBUGGER_EXTENSION_PATH']
> +DEBUGGER = os.environ['DEBUGGER_COMMAND']
> +LLDB = 'lldb' in DEBUGGER
> +EXTENSION = EXTENSION_PATH + ('/luajit_lldb.py' if LLDB else
> '/luajit-gdb.py')
> +TIMEOUT = 10
> +
> +# Don't run any initialization scripts.
> +RUN_CMD_FILE = []
> +
> +if LLDB:
> + RUN_CMD_FILE = [
> + '--batch',
> + '--no-lldbinit',
> + '--no-use-colors',
> + '--source-quietly',
> + '--source'
> + ]
> +else:
> + # GDB.
> + RUN_CMD_FILE = ['--batch', '--nx', '--quiet', '--command']
> +
> +INFERIOR_ARGS = '--' if LLDB else '--args'
> +PROCESS_RUN = 'process launch' if LLDB else 'r'
> +LOAD_EXTENSION = (
> + 'command script import {ext}' if LLDB else 'source {ext}'
> +).format(ext=EXTENSION)
> +
> +
> +RX_ADDR = r'0x[a-f0-9]+'
> +RX_HASH = RX_ADDR # The same pattern for hexademic values.
> +RX_FRAME = r'\[(S|\s)(B|\s)(T|\s)(M|\s)\]'
> +
> +
> +def persist(data):
> + tmp = tempfile.NamedTemporaryFile(mode='w')
> + tmp.write(data)
> + tmp.flush()
> + return tmp
> +
> +
> +def execute_process(cmd, timeout=TIMEOUT):
> + if LEGACY:
> + # XXX: The Python 2.7 version of `subprocess.Popen`
> + # doesn't have a timeout option, so the required
> + # functionality was implemented via `threading.Timer`.
> + process = subprocess.Popen(
> + cmd,
> + stdout=subprocess.PIPE,
> + stderr=subprocess.PIPE,
> + # This prevents sending of SIGSTTOU to the test when
> + # running by `make'. Stdin is unused anyway.
> + stdin=subprocess.DEVNULL
> + )
> + timer = Timer(TIMEOUT, process.kill)
> + timer.start()
> + stdout, _ = process.communicate()
> + timer.cancel()
> +
> + # XXX: If the timeout is exceeded and the process is
> + # killed by the timer, then the return code is non-zero,
> + # and we are going to blow up.
> + assert process.returncode == 0
> + return stdout.decode('ascii')
> + else:
> + process = subprocess.run(
> + cmd,
> + stdout=subprocess.PIPE,
> + stderr=subprocess.PIPE,
> + # This prevents sending of SIGSTTOU to the test when
> + # running by `make'. Stdin is unused anyway.
> + stdin=subprocess.DEVNULL,
> + universal_newlines=True,
> + timeout=TIMEOUT
> + )
> + return process.stdout
> +
> +
> +class TestCaseBase(unittest.TestCase):
> + @classmethod
> + def construct_cmds(cls):
> + return '\n'.join([
> + 'b {loc}'.format(loc=cls.location),
> + PROCESS_RUN,
> + 'n',
> + LOAD_EXTENSION,
> + cls.extension_cmds.strip(),
> + 'q',
> + ])
> +
> + @classmethod
> + def setUpClass(cls):
> + cmd_file = persist(cls.construct_cmds())
> + script_file = persist(cls.lua_script)
> + process_cmd = [
> + DEBUGGER,
> + *RUN_CMD_FILE,
> + cmd_file.name,
> + INFERIOR_ARGS,
> + LUAJIT_BINARY,
> + script_file.name,
> + ]
> + cls.output = execute_process(process_cmd)
> + cmd_file.close()
> + script_file.close()
> +
> + def check(self):
> + if LEGACY:
> + self.assertRegexpMatches(self.output, self.pattern.strip())
> + else:
> + self.assertRegex(self.output, self.pattern.strip())
> +
> +
> +class TestLoad(TestCaseBase):
> + extension_cmds = ''
> + location = 'lj_cf_print'
> + lua_script = 'print(1)'
> + pattern = (
> + r'lj-arch command initialized\n'
> + r'lj-tv command initialized\n'
> + r'lj-str command initialized\n'
> + r'lj-tab command initialized\n'
> + r'lj-stack command initialized\n'
> + r'lj-state command initialized\n'
> + r'lj-gc command initialized\n'
> + r'.*is successfully loaded'
> + )
> +
> +
> +class TestLJArch(TestCaseBase):
> + extension_cmds = 'lj-arch'
> + location = 'lj_cf_print'
> + lua_script = 'print(1)'
> + pattern = (
> + r'LJ_64: (True|False), '
> + r'LJ_GC64: (True|False), '
> + r'LJ_DUALNUM: (True|False)'
> + )
> +
> +
> +class TestLJState(TestCaseBase):
> + extension_cmds = 'lj-state'
> + location = 'lj_cf_print'
> + lua_script = 'print(1)'
> + pattern = (
> + r'VM state: [A-Z]+\n'
> + r'GC state: [A-Z]+\n'
> + r'JIT state: [A-Z]+\n'
> + )
> +
> +
> +class TestLJGC(TestCaseBase):
> + extension_cmds = 'lj-gc'
> + location = 'lj_cf_print'
> + lua_script = 'print(1)'
> + pattern = (
> + r'GC stats: [A-Z]+\n'
> + r'\ttotal: \d+\n'
> + r'\tthreshold: \d+\n'
> + r'\tdebt: \d+\n'
> + r'\testimate: \d+\n'
> + r'\tstepmul: \d+\n'
> + r'\tpause: \d+\n'
> + r'\tsweepstr: \d+/\d+\n'
> + r'\troot: \d+ objects\n'
> + r'\tgray: \d+ objects\n'
> + r'\tgrayagain: \d+ objects\n'
> + r'\tweak: \d+ objects\n'
> + r'\tmmudata: \d+ objects\n'
> + )
> +
> +
> +class TestLJStack(TestCaseBase):
> + extension_cmds = 'lj-stack'
> + location = 'lj_cf_print'
> + lua_script = 'print(1)'
> + pattern = (
> + r'-+ Red zone:\s+\d+ slots -+\n'
> + r'(' + RX_ADDR + r'\s+' + RX_FRAME + r' VALUE: nil\n?)*\n'
> + r'-+ Stack:\s+\d+ slots -+\n'
> + r'(' + RX_ADDR + r'(:' + RX_ADDR + r')?\s+' + RX_FRAME + r'.*\n?)+\n'
> + )
> +
> +
> +class TestLJTV(TestCaseBase):
> + location = 'lj_cf_print'
> + extension_cmds = (
> + 'lj-tv L->base\n'
> + 'lj-tv L->base + 1\n'
> + 'lj-tv L->base + 2\n'
> + 'lj-tv L->base + 3\n'
> + 'lj-tv L->base + 4\n'
> + 'lj-tv L->base + 5\n'
> + 'lj-tv L->base + 6\n'
> + 'lj-tv L->base + 7\n'
> + 'lj-tv L->base + 8\n'
> + 'lj-tv L->base + 9\n'
> + 'lj-tv L->base + 10\n'
> + 'lj-tv L->base + 11\n'
> + )
> +
> + lua_script = (
> + 'local ffi = require("ffi")\n'
> + 'print(\n'
> + ' nil,\n'
> + ' false,\n'
> + ' true,\n'
> + ' "hello",\n'
> + ' {1},\n'
> + ' 1,\n'
> + ' 1.1,\n'
> + ' coroutine.create(function() end),\n'
> + ' ffi.new("int*"),\n'
> + ' function() end,\n'
> + ' print,\n'
> + ' require\n'
> + ')\n'
> + )
> +
> + pattern = (
> + r'nil\n'
> + r'false\n'
> + r'true\n'
> + r'string \"hello\" @ ' + RX_ADDR + r'\n'
> + r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
> + r'(number|integer) .*1.*\n'
> + r'number 1.1\d+\n'
> + r'thread @ ' + RX_ADDR + r'\n'
> + r'cdata @ ' + RX_ADDR + r'\n'
> + r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
> + r'fast function #[0-9]+\n'
> + r'C function @ ' + RX_ADDR + r'\n'
> + )
> +
> +
> +class TestLJStr(TestCaseBase):
> + extension_cmds = (
> + # XXX: Get the value to the stack slot for the variable.
> + 'n\n'
> + 'lj-str fname\n'
> + )
> + location = 'lj_cf_dofile'
> + lua_script = 'pcall(dofile("name"))'
> + pattern = r'String: .* \[\d+ bytes\] with hash ' + RX_HASH
> +
> +
> +class TestLJTab(TestCaseBase):
> + extension_cmds = (
> + # XXX: Get the value to the stack slot for the variable.
> + 'n\n'
> + 'lj-tab t\n'
> + )
> + location = 'lj_cf_unpack'
> + lua_script = 'unpack({1; a = 1})'
> + pattern = (
> + r'Array part: 3 slots\n' +
> + RX_ADDR + r': \[0\]: nil\n' +
> + RX_ADDR + r': \[1\]: .+ 1\n' +
> + RX_ADDR + r': \[2\]: nil\n' +
> + r'Hash part: 2 nodes\n' +
> + RX_ADDR + r': { string "a" @ ' + RX_ADDR + r' } => ' +
> + r'{ .+ 1 }; next = 0x0\n' +
> + RX_ADDR + r': { nil } => { nil }; next = 0x0\n'
> + )
> +
> +
> +for test_cls in TestCaseBase.__subclasses__():
> + test_cls.test = lambda self: self.check()
> +
> +# FIXME: skip for LLDB since most commands are not working anyway.
> +if __name__ == '__main__' and not LLDB:
> + unittest.main(verbosity=2)
> --
> 2.53.0
>
[-- Attachment #2: Type: text/html, Size: 16680 bytes --]
next prev parent reply other threads:[~2026-05-26 13:50 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-19 12:39 [Tarantool-patches] [PATCH v2 luajit 0/6] Unified extension for debuggers Sergey Kaplun via Tarantool-patches
2026-05-19 12:39 ` [Tarantool-patches] [PATCH v2 luajit 1/6] test: introduce tests for debugging extensions Sergey Kaplun via Tarantool-patches
2026-05-20 13:38 ` Sergey Bronnikov via Tarantool-patches
2026-05-25 9:14 ` Sergey Kaplun via Tarantool-patches
2026-05-27 9:54 ` Sergey Bronnikov via Tarantool-patches
2026-05-27 10:52 ` Sergey Kaplun via Tarantool-patches
2026-05-26 13:50 ` Evgeniy Temirgaleev via Tarantool-patches [this message]
2026-05-26 14:41 ` Sergey Kaplun via Tarantool-patches
2026-05-26 18:52 ` Evgeniy Temirgaleev via Tarantool-patches
2026-05-27 7:56 ` Sergey Kaplun via Tarantool-patches
2026-05-27 12:41 ` Sergey Bronnikov via Tarantool-patches
2026-05-19 12:39 ` [Tarantool-patches] [PATCH v2 luajit 2/6] lldb: refactor extension Sergey Kaplun via Tarantool-patches
2026-05-27 12:27 ` Sergey Bronnikov via Tarantool-patches
2026-05-19 12:39 ` [Tarantool-patches] [PATCH v2 luajit 3/6] dbg: sort initialization of commands Sergey Kaplun via Tarantool-patches
2026-05-20 13:43 ` Sergey Bronnikov via Tarantool-patches
2026-05-19 12:39 ` [Tarantool-patches] [PATCH v2 luajit 4/6] lldb: support full-range 64-bit lightuserdata Sergey Kaplun via Tarantool-patches
2026-05-27 12:28 ` Sergey Bronnikov via Tarantool-patches
2026-05-19 12:39 ` [Tarantool-patches] [PATCH v2 luajit 5/6] dbg: generalize extension Sergey Kaplun via Tarantool-patches
2026-05-27 12:38 ` Sergey Bronnikov via Tarantool-patches
2026-05-27 12:55 ` Sergey Kaplun via Tarantool-patches
2026-05-19 12:39 ` [Tarantool-patches] [PATCH v2 luajit 6/6] ci: introduce workflow to test debugger extension Sergey Kaplun via Tarantool-patches
2026-05-20 13:52 ` Sergey Bronnikov via Tarantool-patches
2026-05-25 7:00 ` Sergey Kaplun via Tarantool-patches
2026-05-27 10:57 ` Sergey Bronnikov via Tarantool-patches
2026-05-27 11:58 ` Sergey Kaplun via Tarantool-patches
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1779803427.60260456@f511.i.mail.ru \
--to=tarantool-patches@dev.tarantool.org \
--cc=e.temirgaleev@tarantool.org \
--cc=skaplun@tarantool.org \
--subject='Re: [Tarantool-patches] [PATCH v2 luajit 1/6] test: introduce tests for debugging extensions' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox