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 luajit 2/3] dbg: introduce lj-ctype command, extend cdata dump
Date: Mon, 29 Jun 2026 16:55:49 +0300 [thread overview]
Message-ID: <1782741349.288346286@f466.i.mail.ru> (raw)
In-Reply-To: <20260625202903.3157425-3-skaplun@tarantool.org>
[-- Attachment #1: Type: text/plain, Size: 20368 bytes --]
Hi, Sergey!
Thanks for the patch!
Please, see the commends below.
--
Best regards,
Evgeniy Temirgaleev
>
> From: Sergey Kaplun <skaplun@tarantool.org>
> To: Sergey Bronnikov <sergeyb@tarantool.org>, Evgeniy Temirgaleev <e.temirgaleev@tarantool.org
> >
> Cc: tarantool-patches@dev.tarantool.org, Sergey Kaplun <skaplun@tarantool.org
> >
> Date: Thursday, June 25, 2026 11:29 PM +03:00
> 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.
>
Is /unsigned/uint64_t/ clearly?
>
> + 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):
>
May we name this function ‘CTINFO’ as in ‘lj_ctype.h’? Or leave a comment with an original name for quick grep.
>
> + 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):
>
Let’s put these function definitions in the ‘lj_ctype.h’ order?
May we group the definitions by corresponding C files also? # lj_ctype.h … # lj_cdata.h … # lj_xxx.c …
>
> + 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:
>
assert for size == 8 ?
>
> + 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):
>
Func proto differs with lj_ctype.c (static void ctype_prepnum(CTRepr *ctr, uint32_t n)).
It seems, you move some of ctype_repr() code here. Let’s comment it?
>
> + 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):
>
Also, it seems, it will be easy to read to code, if it will be possible to distinguish between ported functions and extension itself ones. May be by use the ‘dbg_’ prefix for extension function names.
>
> + 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.
>
The extension command set is common for GDB and LLDB. Does we skip for GDB also?
>
> + '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
>
[-- Attachment #2: Type: text/html, Size: 24755 bytes --]
next prev parent reply other threads:[~2026-06-29 13:56 UTC|newest]
Thread overview: 9+ 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-28 1:03 ` Evgeniy Temirgaleev via Tarantool-patches
2026-06-28 16:32 ` Sergey Kaplun via Tarantool-patches
2026-06-25 20:29 ` [Tarantool-patches] [PATCH luajit 2/3] dbg: introduce lj-ctype command, extend cdata dump Sergey Kaplun via Tarantool-patches
2026-06-29 13:55 ` Evgeniy Temirgaleev 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
2026-06-28 1:31 ` Evgeniy Temirgaleev via Tarantool-patches
2026-06-28 15:19 ` 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=1782741349.288346286@f466.i.mail.ru \
--to=tarantool-patches@dev.tarantool.org \
--cc=e.temirgaleev@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