From: Sergey Kaplun via Tarantool-patches <tarantool-patches@dev.tarantool.org>
To: Sergey Bronnikov <sergeyb@tarantool.org>,
Evgeniy Temirgaleev <e.temirgaleev@tarantool.org>
Cc: tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [PATCH luajit 2/3] dbg: introduce lj-ctype command, extend cdata dump
Date: Thu, 25 Jun 2026 23:29:02 +0300 [thread overview]
Message-ID: <20260625202903.3157425-3-skaplun@tarantool.org> (raw)
In-Reply-To: <20260625202903.3157425-1-skaplun@tarantool.org>
This patch extends dumped information for the given cdata object. Now
it resolves the given `CType` and prints it in the format similar to the
`__tostring` metamethod. The `lj-ctype` command is introduced to dump
this information where there is only the `CType` pointer but no cdata
associated with it.
`__or__` and `__ror__` metamethods are monkey-patched for the LLDB value
object. In `__sub__` metamethod for LLDB pointers `GetPointeeType()` is
used to get the pointee type instead of the incorrectly used
`GetDereferencedType()` which always returns the same type with size 8.
Casting from negative values to the unsigned values is supported to
check `CTF_UCHAR`.
Part of tarantool/tarantool#4808
---
src/luajit_dbg.py | 333 +++++++++++++++++-
.../debug-extension-tests.py | 208 ++++++++++-
2 files changed, 535 insertions(+), 6 deletions(-)
diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index fd6ca8a5..62cd65d5 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -386,6 +386,8 @@ class _LLDBDebugger(Debugger):
pack_flag = '<q'
else:
pack_flag = '<Q'
+ # Cast to unsigned.
+ raw_value &= 0xFFFFFFFFFFFFFFFF
raw_data = struct.pack(pack_flag, raw_value)
sbdata = lldb.SBData()
sbdata.SetData(
@@ -482,6 +484,9 @@ class _LLDBDebugger(Debugger):
def lldb__lt__(lldbval, other):
return int(lldbval) < int(other)
+ def lldb__or__(lldbval, other):
+ return int(lldbval) | int(other)
+
def lldb__str__(lldbval):
# Instead of default GetSummary.
if not lldbval.sbvalue.TypeIsPointerType():
@@ -512,8 +517,8 @@ class _LLDBDebugger(Debugger):
lldbval_tp = sbval.GetType()
other_tp = osbval.GetType()
# Subtract pointers of the same size only.
- elsz = lldbval_tp.GetDereferencedType().size
- if other_tp.GetDereferencedType().size != elsz:
+ elsz = lldbval_tp.GetPointeeType().size
+ if other_tp.GetPointeeType().size != elsz:
raise Exception(
'Attempt to substruct {otp} from {stp}'.format(
stp=lldbval_tp.name,
@@ -536,6 +541,8 @@ class _LLDBDebugger(Debugger):
lldb.value.__index__ = lldb__index__
lldb.value.__le__ = lldb__le__
lldb.value.__lt__ = lldb__lt__
+ lldb.value.__or__ = lldb__or__
+ lldb.value.__ror__ = lldb__or__ # Same semantics.
lldb.value.__str__ = lldb__str__
lldb.value.__sub__ = lldb__sub__
@@ -1352,6 +1359,119 @@ def lightudV(tv):
return gcval(tv['gcr'])
+# FFI.
+
+
+def ctype_ctsG(g):
+ return mref('CTState *', g['ctype_state'])
+
+
+def ctype_get(cts, id):
+ return dbg.address(cts['tab'][id])
+
+
+# Externally visible types.
+CT_NUM = 0 # Integer or floating-point numbers.
+CT_STRUCT = 1 # Struct or union.
+CT_PTR = 2 # Pointer or reference.
+CT_ARRAY = 3 # Array or complex type.
+CT_MAYCONVERT = CT_ARRAY
+CT_VOID = 4 # Void type.
+CT_ENUM = 5 # Enumeration.
+CT_HASSIZE = CT_ENUM # Last type where ct->size holds the actual size.
+CT_FUNC = 6 # Function.
+CT_TYPEDEF = 7 # Typedef.
+CT_ATTRIB = 8 # Miscellaneous attributes.
+
+# Common types.
+CTID_CTYPEID = 21
+
+# C type info flags.
+CTF_BOOL = 0x08000000 # Boolean: NUM, BITFIELD.
+CTF_FP = 0x04000000 # Floating-point: NUM.
+CTF_CONST = 0x02000000 # Const qualifier.
+CTF_VOLATILE = 0x01000000 # Volatile qualifier.
+CTF_UNSIGNED = 0x00800000 # Unsigned: NUM, BITFIELD.
+CTF_LONG = 0x00400000 # Long: NUM.
+CTF_VLA = 0x00100000 # Variable-length: ARRAY, STRUCT.
+CTF_REF = 0x00800000 # Reference: PTR.
+CTF_VECTOR = 0x08000000 # Vector: ARRAY.
+CTF_COMPLEX = 0x04000000 # Complex: ARRAY.
+CTF_UNION = 0x00800000 # Union: STRUCT.
+CTF_VARARG = 0x00800000 # Vararg: FUNC.
+CTF_SSEREGPARM = 0x00400000 # SSE register parameters: FUNC.
+
+CTF_UCHAR = CTF_UNSIGNED if int(dbg.cast('char', -1)) > 0 else 0
+
+CTMASK_ATTRIB = 255 # Max. 256 attributes.
+CTSHIFT_ATTRIB = 16
+
+# Attribute numbers.
+CTA_QUAL = 1 # Unmerged qualifiers.
+
+CTSHIFT_NUM = 28
+CTMASK_CID = 0x0000ffff
+CTMASK_NUM = 0xf0000000 # Max. 16 type numbers.
+
+# Special sizes.
+CTSIZE_INVALID = 0xffffffff
+DWORDSZ = 4
+QWORDSZ = 8
+
+
+def ctype_type(info):
+ return info >> CTSHIFT_NUM
+
+
+def ctype_attrib(info):
+ return (info >> CTSHIFT_ATTRIB) & CTMASK_ATTRIB
+
+
+def ctinfo(ct, flags):
+ return (tou32(ct) << CTSHIFT_NUM) + flags
+
+
+def ctype_isptr(info):
+ return ctype_type(info) == CT_PTR
+
+
+def ctype_iscomplex(info):
+ return (info & (CTMASK_NUM | CTF_COMPLEX)) == ctinfo(CT_ARRAY, CTF_COMPLEX)
+
+
+def ctype_isinteger(info):
+ return (info & (CTMASK_NUM | CTF_BOOL | CTF_FP)) == ctinfo(CT_NUM, 0)
+
+
+def ctype_isrefarray(info):
+ return (info & (CTMASK_NUM | CTF_VECTOR | CTF_COMPLEX)) == \
+ ctinfo(CT_ARRAY, 0)
+
+
+def ctype_cid(info):
+ return info & CTMASK_CID
+
+
+def ctype_child(cts, ctype):
+ return ctype_get(cts, ctype_cid(ctype['info']))
+
+
+def cdataptr(cd):
+ return dbg.cast('void *', (cd + 1))
+
+
+def cdata_getptr(p, size):
+ if LJ_64 and size == 4:
+ return dbg.cast('void *', dbg.cast('uint32_t *', p)[0])
+ else:
+ return dbg.cast('void *', dbg.cast('uint64_t *', p)[0])
+
+
+# Get C type ID for a C type.
+def ctype_typeid(cts, ct):
+ return ct - cts['tab']
+
+
# JIT engine.
@@ -1951,7 +2071,26 @@ def dump_lj_gco_trace(gcobj):
def dump_lj_gco_cdata(gcobj):
- return 'cdata @ {}'.format(strx64(gcobj))
+ cdata = dbg.cast('struct GCcdata *', gcobj)
+ cts = ctype_ctsG(G(L()))
+ cid = cdata['ctypeid']
+ ctype = ctype_get(cts, cid)
+ info = ctype['info']
+ size = ctype['size']
+ value = ''
+ if ctype_iscomplex(info):
+ value = cdata_val_complex(cdata, ctype)
+ elif size == 8 and ctype_isinteger(info):
+ value = cdata_val_int64(cdata, ctype)
+ else:
+ value = cdataptr(cdata)
+ if ctype_isptr(info):
+ value = cdata_getptr(value, size)
+ return 'cdata @ {addr} {ctype} {value}'.format(
+ addr=strx64(gcobj),
+ ctype=dump_ctype(ctype),
+ value=value,
+ )
def dump_lj_gco_tab(gcobj):
@@ -2281,6 +2420,176 @@ def dump_func(func):
return 'fast function #{}\n'.format(int(ffid))
+# FFI dumpers.
+
+
+def cdata_val_int64(cdata, ctype):
+ info = ctype['info']
+ isunsigned = info & CTF_UNSIGNED
+ cdataval = cdataptr(cdata)
+ valueptr = None
+ usuffix = ''
+ if isunsigned:
+ usuffix = 'U'
+ valueptr = dbg.cast('uint64_t *', cdataval)
+ else:
+ valueptr = dbg.cast('int64_t *', cdataval)
+ return str(valueptr[0]) + usuffix + 'LL'
+
+
+def cdata_val_complex(cdata, ctype):
+ size = ctype['size']
+ cdataval = cdataptr(cdata)
+ casttype = None
+ if size == QWORDSZ * 2:
+ casttype = 'double *'
+ else:
+ assert size == DWORDSZ * 2, 'bad (complex float) size'
+ casttype = 'float *'
+ re = dbg.cast(casttype, cdataval)[0]
+ im = dbg.cast(casttype, cdataval)[1]
+ sign = '+' if im > 0 else ''
+ return '{re}{sign}{im}i'.format(re=re, im=im, sign=sign)
+
+
+def ctype_preplit(ctypestr, lit):
+ # Prevent extra space in the end of the string.
+ space = ' ' if ctypestr != '' else ''
+ return lit + space + ctypestr
+
+
+def ctype_prepqual(ctypestr, info):
+ if (info & CTF_VOLATILE):
+ ctypestr = ctype_preplit(ctypestr, 'volatile')
+ if (info & CTF_CONST):
+ ctypestr = ctype_preplit(ctypestr, 'const')
+ return ctypestr
+
+
+def ctype_preptype(cts, ctypestr, ctype, qual, tp):
+ nameref = gcref(ctype['name'])
+ if nameref:
+ ctypestr = ctype_preplit(ctypestr, re.sub('"', '', strdata(nameref)))
+ else:
+ ctypestr = ctype_preplit(ctypestr, str(ctype_typeid(cts, ctype)))
+ ctypestr = ctype_preplit(ctypestr, tp)
+ ctypestr = ctype_prepqual(ctypestr, qual)
+ return ctypestr
+
+
+def ctype_prepnum(ctypestr, info, size):
+ if info & CTF_BOOL:
+ ctypestr = ctype_preplit(ctypestr, 'bool')
+ elif info & CTF_FP:
+ if size == QWORDSZ:
+ ctypestr = ctype_preplit(ctypestr, 'double')
+ elif size == DWORDSZ:
+ ctypestr = ctype_preplit(ctypestr, 'float')
+ else:
+ assert size == QWORDSZ * 2, 'bad (long double) size'
+ ctypestr = ctype_preplit(ctypestr, 'long double')
+ elif size == 1:
+ if not ((info ^ CTF_UCHAR) & CTF_UNSIGNED):
+ ctypestr = ctype_preplit(ctypestr, 'char')
+ elif CTF_UCHAR:
+ ctypestr = ctype_preplit(ctypestr, 'signed char')
+ else:
+ ctypestr = ctype_preplit(ctypestr, 'unsigned char')
+ elif size < 8:
+ if size == 4:
+ ctypestr = ctype_preplit(ctypestr, 'int')
+ else:
+ assert size == DWORDSZ // 2, 'bad (short) size'
+ ctypestr = ctype_preplit(ctypestr, 'short')
+ if info & CTF_UNSIGNED:
+ ctypestr = ctype_preplit(ctypestr, 'unsigned')
+ else:
+ size_t = '{u}int{sz}_t'.format(
+ u='u' if info & CTF_UNSIGNED else '',
+ sz=size * 8,
+ )
+ ctypestr = ctype_preplit(ctypestr, size_t)
+ return ctypestr
+
+
+def ctype_repr(cts, id):
+ ctype = ctype_get(cts, id)
+ ctypestr = ''
+ qual = 0
+ ptrto = 0
+ while True:
+ info = ctype['info']
+ size = ctype['size']
+ ctp = ctype_type(info)
+ if ctp == CT_NUM:
+ ctypestr = ctype_prepnum(ctypestr, info, size)
+ return ctype_prepqual(ctypestr, qual | info)
+ elif ctp == CT_VOID:
+ ctypestr = ctype_preplit(ctypestr, 'void')
+ return ctype_prepqual(ctypestr, qual | info)
+ elif ctp == CT_STRUCT:
+ tp = 'union' if (info & CTF_UNION) else 'struct'
+ return ctype_preptype(cts, ctypestr, ctype, qual, tp)
+ elif ctp == CT_ENUM:
+ if id == CTID_CTYPEID:
+ return ctype_preplit(ctypestr, 'ctype')
+ return ctype_preptype(cts, ctypestr, ctype, qual, 'enum')
+ elif ctp == CT_ATTRIB:
+ if ctype_attrib(info) == CTA_QUAL:
+ qual |= size
+ elif ctp == CT_PTR:
+ if info & CTF_REF:
+ ctypestr = ctype_preplit(ctypestr, '&')
+ else:
+ ctypestr = ctype_prepqual(ctypestr, qual | info)
+ if LJ_64 and size == 4:
+ ctypestr = ctype_preplit(ctypestr, '__ptr32')
+ ctypestr = ctype_preplit(ctypestr, '*')
+ qual = 0
+ ptrto = 1
+ elif ctp == CT_ARRAY:
+ if ctype_isrefarray(info):
+ if ptrto:
+ ptrto = 0
+ ctypestr = '(' + ctypestr + ')'
+ arrsize = ''
+ if size != CTSIZE_INVALID:
+ child_size = ctype_child(cts, ctype)['size']
+ arrsize = str(int(size / child_size) if child_size > 0
+ else 0)
+ elif info & CTF_VLA:
+ arrsize = '?'
+ ctypestr = ctypestr + '[{}]'.format(arrsize)
+ elif ctype_iscomplex(info):
+ if size == DWORDSZ * 2:
+ ctypestr = ctype_preplit(ctypestr, 'float')
+ else:
+ assert size == QWORDSZ * 2, 'bad (complex double) size'
+ return ctype_preplit(ctypestr, 'complex')
+ else:
+ ctypestr = ctype_preplit(
+ ctypestr,
+ '__attribute__((vector_size({})))'.format(size)
+ )
+ elif ctp == CT_FUNC:
+ if ptrto:
+ ptrto = 0
+ ctypestr = '(' + ctypestr + ')'
+ ctypestr += '()'
+ ctype = ctype_child(cts, ctype)
+ return 'NYI'
+
+
+def dump_ctype(ct):
+ cts = ctype_ctsG(G(L()))
+ cid = ctype_typeid(cts, ct)
+ name = ctype_repr(cts, cid)
+ return '[{id}] <{name}>'.format(
+ id=cid,
+ name=name,
+ )
+
+
# JIT dumpers.
@@ -2294,7 +2603,8 @@ def dump_call_func(trace, callop):
assert IRS[cdt_idx_irk['o']] == 'KINT', \
'unexpected IR for ctype storage'
ctype_idx = cdt_idx_irk['i']
- ctype = 'ctype: {}'.format(ctype_idx)
+ cts = ctype_ctsG(G(L()))
+ ctype = 'ctype: {}'.format(dump_ctype(ctype_get(cts, ctype_idx)))
func_str = ''
if callop < 0:
@@ -2652,6 +2962,20 @@ https://github.com/tarantool/tarantool/wiki/LuaJIT-Bytecodes.
))
+class LJDumpCType(dbg.LJBase):
+ '''
+lj-ctype <CType *>
+
+The command receives a pointer <ctype> of the corresponding CType
+and dumps the ID and the name for this C data type.
+ '''
+
+ def execute(self, arg):
+ dbg.write('{}\n'.format(
+ dump_ctype(dbg.cast('CType *', dbg.eval(arg)))
+ ))
+
+
class LJDumpFunc(dbg.LJBase):
'''
lj-func <GCfunc *>
@@ -2979,6 +3303,7 @@ def load(event=None):
dbg.initialize_extension({
'lj-arch': LJDumpArch,
'lj-bc': LJDumpBC,
+ 'lj-ctype': LJDumpCType,
'lj-func': LJDumpFunc,
'lj-gc': LJGC,
'lj-gco': LJDumpGCobj,
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 76543daa..fc5d2c7b 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -227,6 +227,7 @@ class TestLoad(TestCaseBase):
pattern = (
r'lj-arch command initialized\n'
r'lj-bc command initialized\n'
+ r'lj-ctype command initialized\n'
r'lj-func command initialized\n'
r'lj-gc command initialized\n'
r'lj-gco command initialized\n'
@@ -331,7 +332,7 @@ GCO_RX = (
r'Lua function @ ' + RX_ADDR + r', [0-9]+ upvalues, .+:[0-9]+\n'
r'C function @ ' + RX_ADDR + r'\n'
r'fast function #[0-9]+\n'
- r'cdata @ ' + RX_ADDR + r'\n'
+ r'cdata @ ' + RX_ADDR + r' \[\d+\] <int \*> 0x0\n'
r'table @ ' + RX_ADDR + r' \(asize: \d+, hmask: ' + RX_HASH + r'\)\n'
r'userdata @ ' + RX_ADDR + r'\n'
)
@@ -817,7 +818,9 @@ class TestLJIRCallXSCType(TestCaseBase):
'trace()\n'
'print()\n'
)
- pattern = r'int CALLXS .* [' + RX_ADDR + r'\]\(.*\) ctype: \d+'
+ pattern = (
+ r'int CALLXS .* [' + RX_ADDR + r'\]\(.*\) ctype: \[\d+\] <int \(\)>'
+ )
class TestLJJSlotsBase(TestCaseBase):
@@ -838,6 +841,207 @@ class TestLJJSlotsBase(TestCaseBase):
)
+def cdata_rx(tpstr, suffix=None):
+ return r'cdata @ ' + RX_ADDR + r' \[\d+\] <' + tpstr + '> ' + (
+ RX_ADDR if not suffix else suffix
+ )
+
+
+CHAR_SIGNED = machine in ['arm64', 'aarch64'] and sys.platform != 'darwin'
+HAS_LONG_DOUBLE = not (machine in ['arm64', 'aarch64'] and
+ sys.platform == 'darwin')
+
+
+class TestLJCTypePrim(TestCaseBase):
+ location = 'lj_cf_print'
+ extension_cmds = (
+ 'n\n' # Load L.
+ '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'
+ 'lj-tv L->base + 12\n'
+ 'lj-tv L->base + 13\n'
+ 'lj-tv L->base + 14\n'
+ 'lj-tv L->base + 15\n'
+ 'lj-tv L->base + 16\n'
+ 'lj-tv L->base + 17\n'
+ 'lj-tv L->base + 18\n'
+ 'lj-tv L->base + 19\n'
+ 'lj-tv L->base + 20\n'
+ 'lj-tv L->base + 21\n'
+ 'lj-tv L->base + 22\n'
+ )
+ lua_script = (
+ 'local ffi = require("ffi")\n'
+ 'print(\n'
+ ' ffi.new("bool"),\n'
+ ' ffi.new("char"),\n'
+ ' ffi.new("signed char"),\n'
+ ' ffi.new("unsigned char"),\n'
+ ' ffi.new("int"),\n'
+ ' ffi.new("short"),\n'
+ ' ffi.new("unsigned"),\n'
+ ' ffi.new("int8_t"),\n'
+ ' ffi.new("int16_t"),\n'
+ ' ffi.new("int32_t"),\n'
+ ' ffi.new("int64_t"),\n'
+ ' ffi.new("uint8_t"),\n'
+ ' ffi.new("uint64_t"),\n'
+ ' ffi.new("float"),\n'
+ ' ffi.new("double"),\n'
+ ' ffi.new("long double"),\n'
+ ' 1i,\n'
+ ' ffi.new("complex float", 1, -2),\n'
+ ' ffi.new("const volatile int"),\n'
+ ' ffi.new("void *"),\n'
+ ' ffi.new("void * __ptr32"),\n'
+ ' ffi.new("int &"),\n'
+ ' ffi.typeof(1LL)\n'
+ ')\n'
+ )
+ pattern = (
+ cdata_rx('bool') + r'\n' +
+ cdata_rx('char') + r'\n' +
+ cdata_rx(('signed ' if CHAR_SIGNED else '') + 'char') + r'\n' +
+ cdata_rx(('unsigned ' if not CHAR_SIGNED else '') + 'char') + r'\n' +
+ cdata_rx('int') + r'\n' +
+ cdata_rx('short') + r'\n' +
+ cdata_rx('unsigned int') + r'\n' +
+ cdata_rx(('signed ' if CHAR_SIGNED else '') + 'char') + r'\n' +
+ cdata_rx('short') + r'\n' +
+ cdata_rx('int') + r'\n' +
+ cdata_rx('int64_t', '0LL') + r'\n' +
+ cdata_rx(('unsigned ' if not CHAR_SIGNED else '') + 'char') + r'\n' +
+ cdata_rx('uint64_t', '0ULL') + r'\n' +
+ cdata_rx('float') + r'\n' +
+ cdata_rx('double') + r'\n' +
+ cdata_rx(('long ' if HAS_LONG_DOUBLE else '') + 'double') + r'\n' +
+ cdata_rx('complex', r'0\+1i') + r'\n' +
+ cdata_rx('complex float', '1-2i') + r'\n' +
+ cdata_rx('const volatile int') + r'\n' +
+ cdata_rx(r'void \*') + r'\n' +
+ cdata_rx(r'void \* __ptr32') + r'\n' +
+ cdata_rx('int &') + r'\n' +
+ cdata_rx('ctype') + r'\n'
+ )
+
+
+class TestLJCTypeStructUnionEnum(TestCaseBase):
+ location = 'lj_cf_print'
+ extension_cmds = (
+ 'n\n' # Load L.
+ 'lj-tv L->base\n'
+ 'lj-tv L->base + 1\n'
+ 'lj-tv L->base + 2\n'
+ 'lj-tv L->base + 3\n'
+ )
+ lua_script = (
+ 'local ffi = require("ffi")\n'
+ 'ffi.cdef[[\n'
+ ' struct test {int a;};\n'
+ ']]\n'
+ 'print(\n'
+ ' ffi.new("struct test"),\n'
+ ' ffi.new("struct {int a;}"),\n'
+ ' ffi.new("union {int a;}"),\n'
+ ' ffi.new("enum {ENUM1}")\n'
+ ')\n'
+ )
+ pattern = (
+ cdata_rx('struct test') + r'\n' +
+ cdata_rx(r'struct \d+') + r'\n' +
+ cdata_rx(r'union \d+') + r'\n' +
+ cdata_rx(r'enum \d+') + r'\n'
+ )
+
+
+class TestLJCTypeArray(TestCaseBase):
+ location = 'lj_cf_print'
+ extension_cmds = (
+ 'n\n' # Load L.
+ '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'
+ )
+ lua_script = (
+ 'local ffi = require("ffi")\n'
+ 'print(\n'
+ ' ffi.new("char [0]"),\n'
+ ' ffi.new("int [1]"),\n'
+ ' ffi.new("complex [2]"),\n'
+ ' ffi.new("complex float [3]"),\n'
+ ' ffi.new("float __attribute__((vector_size(4)))"),\n'
+ ' ffi.new("int (&)[5]"),\n'
+ ' ffi.new("int[?]", 6)\n'
+ ')\n'
+ )
+ pattern = (
+ cdata_rx(r'char \[0\]') + r'\n' +
+ cdata_rx(r'int \[1\]') + r'\n' +
+ cdata_rx(r'complex \[2\]') + r'\n' +
+ cdata_rx(r'complex float \[3\]') + r'\n' +
+ cdata_rx(r'float __attribute__\(\(vector_size\(4\)\)\)') + r'\n' +
+ cdata_rx(r'int \(&\)\[5\]') + r'\n' +
+ cdata_rx(r'int \[\?\]') + r'\n'
+ )
+
+
+class TestLJCTypeFunc(TestCaseBase):
+ location = 'lj_cf_print'
+ extension_cmds = (
+ 'n\n' # Load L.
+ 'lj-tv L->base\n'
+ 'lj-tv L->base + 1\n'
+ 'lj-tv L->base + 2\n'
+ )
+ lua_script = (
+ 'local ffi = require("ffi")\n'
+ 'ffi.cdef[[void getpid(void);]]\n'
+ 'print(\n'
+ ' ffi.C.getpid,\n'
+ ' ffi.new("int (*)()"),\n'
+ ' ffi.new("int (*(*)(void))[2]")\n'
+ ')\n'
+ )
+ pattern = (
+ cdata_rx(r'void \(\)') + r'\n' +
+ cdata_rx(r'int \(\*\)\(\)') + r'\n' +
+ cdata_rx(r'int \(\* \(\*\)\(\)\)\[2\]') + r'\n'
+ )
+
+
+class TestLJCTypeBase(TestCaseBase):
+ location = 'lj_cf_ffi_new'
+ extension_cmds = (
+ # Load `ct`. Skip inlined functions for LLDB.
+ 'n\n'
+ 'n\n'
+ 'n\n'
+ 'n\n'
+ 'n\n'
+ 'n\n'
+ 'lj-ctype ct\n'
+ )
+ lua_script = (
+ 'local ffi = require("ffi")\n'
+ 'ffi.new("int")\n'
+ )
+ pattern = r'\[\d+\] <int>'
+
+
for test_cls in TestCaseBase.__subclasses__():
test_cls.test = lambda self: self.check()
--
2.54.0
next prev parent reply other threads:[~2026-06-25 20:30 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-25 20:29 [Tarantool-patches] [PATCH luajit 0/3] Extend debug extension Sergey Kaplun via Tarantool-patches
2026-06-25 20:29 ` [Tarantool-patches] [PATCH luajit 1/3] dbg: introduce lj-ir, lj-jslots, lj-trace dumpers Sergey Kaplun via Tarantool-patches
2026-06-25 20:29 ` Sergey Kaplun via Tarantool-patches [this message]
2026-06-25 20:29 ` [Tarantool-patches] [PATCH luajit 3/3] test: add verbose mode for debug extension tests 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=20260625202903.3157425-3-skaplun@tarantool.org \
--to=tarantool-patches@dev.tarantool.org \
--cc=e.temirgaleev@tarantool.org \
--cc=sergeyb@tarantool.org \
--cc=skaplun@tarantool.org \
--subject='Re: [Tarantool-patches] [PATCH luajit 2/3] dbg: introduce lj-ctype command, extend cdata dump' \
/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