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