From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 475F26EFF0; Fri, 5 Jun 2026 17:55:48 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 475F26EFF0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1780671348; bh=Y+7uG/cL0cRTZVqgbatyxxL/JAqvfiXRH2x8FBAjgyw=; h=Date:To:Cc:References:In-Reply-To:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=JNSQZnMDR2OKlL/bj7L5VRLCZaw4dQJJmUkik2oZlfmwH5UqCmlQGLGasLyo34mfB K1VrBZAmyS8VUauWFOCcwSfBt+WgWQWGAsdCuQeNX96nJnZlFk6pCMkf3nnTS2OZfC sfRFZBNKdnq7VdVUTOkWxWqlH00CvLKiUE5lc6VI= Received: from send59.i.mail.ru (send59.i.mail.ru [89.221.237.154]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 466A86EFF0 for ; Fri, 5 Jun 2026 17:55:41 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 466A86EFF0 Received: by exim-smtp-85dd497b6-xnkv4 with esmtpa (envelope-from ) id 1wVVxU-00000000IPP-11l9; Fri, 05 Jun 2026 17:55:40 +0300 Content-Type: multipart/alternative; boundary="------------nL905PWFZeJCLlOTJuyG0OOR" Message-ID: Date: Fri, 5 Jun 2026 17:55:39 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US To: Sergey Kaplun , Evgeniy Temirgaleev Cc: tarantool-patches@dev.tarantool.org References: <20260604093052.2221827-1-skaplun@tarantool.org> <20260604093052.2221827-2-skaplun@tarantool.org> In-Reply-To: <20260604093052.2221827-2-skaplun@tarantool.org> X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: EEAE043A70213CC8 X-77F55803: 4F1203BC0FB41BD9421AE2B81725B364B0C808115EE27B1CF60488447F024E2F1313CFAB8367EF908E2BE116634AD74D289041261DE7A917C7D0F6C13AE992137DBFD6CAFBD361D1C1C35EE3C533BCA44DF7BC4678047644 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE70043D879A87EF1BCEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637FE9EFE935CD7C6AE8638F802B75D45FF914D58D5BE9E6BC1A93B80C6DEB9DEE97C6FB206A91F05B2E439F242B40DC0622E070BE324C7D3C431D0E6894B81D1ACF6B57BC7E64490618DEB871D839B73339E8FC8737B5C22494854413538E1713FCC7F00164DA146DAFE8445B8C89999729449624AB7ADAF37F6B57BC7E64490611E7FA7ABCAF51C92176DF2183F8FC7C0ECC8AC47CD0EDEFF8941B15DA834481F9449624AB7ADAF372E808ACE2090B5E14AD6D5ED66289B5259CC434672EE63711DD303D21008E298D5E8D9A59859A8B6B372FE9A2E580EFC725E5C173C3A84C3A27B50A64E76B53235872C767BF85DA2F004C90652538430E4A6367B16DE6309 X-C1DE0DAB: 0D63561A33F958A5F6B6B2AC40030DE85002B1117B3ED696D9B8A015B4E1F4B0559C6C5561145D6F3610D81D389A125CDE35189EBF2DEA28FEA14CD2CD220BB99C5DF10A05D560A9880EC71AF561E0AAD9143641EC25BB397C6342DCCD0FE4D8 X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34CAB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D65971A41314B67CC1F4EF01B03534A36FBA3FFBEF4AED010C4B8331F070186E276B9407938D09C61AFAB8341EE9D5BE9A0AECBD54B4C3C7FE2AD080BCB354A7D96158CEC1C868D7ABD36536EB022892E5344C41F94D744909CE2512F26BEC029E55448553D2254B8D95CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXMZebaIdHP2ghjoIc/363UZI6Kf1ptIMVRI2994ruhLUGxuP7kSoJvc= X-DA7885C5: C7E193E1AE04F24DF255D290C0D534F91EAE35599EDB55AD5C491356B72B61EE830012424EAB62B05B1A4C17EAA7BC4BEF2421ABFA55128DAF83EF9164C44C7E X-Mailru-Sender: 689FA8AB762F7393520AF17B8A65FDE2D40807768F6A8499CBB986052ED3463BBFBA372BA54F9188EF86D5F70DA33880E41E8EF7A07863ECB274557F927329BE2DDF8182D28ACDB545BD1C3CC395C826B4A721A3011E896F X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH luajit 1/4] dbg: fix lj-stack command for LLDB X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Bronnikov via Tarantool-patches Reply-To: Sergey Bronnikov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" This is a multi-part message in MIME format. --------------nL905PWFZeJCLlOTJuyG0OOR Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hi, Sergey, thanks for the patch! LGTM On 6/4/26 12:30, Sergey Kaplun wrote: > This commit is the follow-up for the commit > 593fef813b7d36060e0c1b1ae2df0fbc0d604d1f ("lldb: refactor extension"). > `GetValueForExpressionPath()` may produce the empty value for negative > indexes. This leads to incorrect frame unwinding in the LLDB extension > and errors like: > | Failed to execute command `lj-stack`: > | 'Q' format requires 0 <= number <= 18446744073709551615 > > This patch adds special handling for the negative indices. > --- > src/luajit_dbg.py | 49 ++++++++++++++++--- > .../debug-extension-tests.py | 26 +++++++--- > 2 files changed, 62 insertions(+), 13 deletions(-) > > diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py > index d9196f06..410f0191 100644 > --- a/src/luajit_dbg.py > +++ b/src/luajit_dbg.py > @@ -255,15 +255,31 @@ class _GDBDebugger(Debugger): > > class _LLDBDebugger(Debugger): > def _lldb_tp_isfp(self, tp): > - return tp.GetBasicType() in [ > + return tp.GetCanonicalType().GetBasicType() in [ > lldb.eBasicTypeFloat, > lldb.eBasicTypeDouble, > lldb.eBasicTypeLongDouble > ] > > + def _lldb_tp_issigned(self, tp): > + return tp.GetCanonicalType().GetBasicType() in [ > + lldb.eBasicTypeChar, > + lldb.eBasicTypeSignedChar, > + lldb.eBasicTypeShort, > + lldb.eBasicTypeInt, > + lldb.eBasicTypeLong, > + lldb.eBasicTypeLongLong, > + lldb.eBasicTypeInt128 > + ] > + > def _lldb_value_from_raw(self, raw_value, size, tp): > isfp = self._lldb_tp_isfp(tp) > - pack_flag = ' + if isfp: > + pack_flag = ' + elif self._lldb_tp_issigned(tp): > + pack_flag = ' + else: > + pack_flag = ' raw_data = struct.pack(pack_flag, raw_value) > sbdata = lldb.SBData() > sbdata.SetData( > @@ -308,9 +324,24 @@ class _LLDBDebugger(Debugger): > key = int(key) > if type(key) is int: > # Allow array access. > - return lldb.value( > - lldbval.sbvalue.GetValueForExpressionPath('[%i]' % key) > - ) > + if key >= 0: > + return lldb.value( > + lldbval.sbvalue.GetValueForExpressionPath('[%i]' % key) > + ) > + else: > + # GetValueForExpressionPath doesn't work for > + # negative offsets. > + sbvalue = lldbval.sbvalue > + assert sbvalue.TypeIsPointerType(), \ > + 'attempt to get index of non-pointer type' > + tp = sbvalue.GetType().GetPointeeType() > + sz = sbvalue.deref.size > + addr = sbvalue.GetValueAsUnsigned() + key * sz > + return lldb.value(self.target.CreateValueFromAddress( > + '({tp}){addr}'.format(tp=tp, addr=addr), > + lldb.SBAddress(addr, self.target), > + tp, > + )) > elif type(key) is str: > return lldb.value(lldbval.sbvalue.GetChildMemberWithName(key)) > raise Exception(TypeError('No item of type %s' % str(type(key)))) > @@ -417,8 +448,12 @@ class _LLDBDebugger(Debugger): > # may take the 8 bytes of memory instead of 4, before the > # cast. Construct the value on the fly. > tp = self._dbgtype(typestr) > - is_fp = self._lldb_tp_isfp(tp) > - rawval = float(val.GetValue()) if is_fp else val.GetValueAsUnsigned() > + if self._lldb_tp_isfp(tp): > + rawval = float(val.GetValue()) > + elif self._lldb_tp_issigned(tp): > + rawval = val.GetValueAsSigned() > + else: > + rawval = val.GetValueAsUnsigned() > return self._lldb_value_from_raw(rawval, val.GetByteSize(), tp) > > def sizeof(self, typestr): > diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py > index 61529561..7cb60d84 100644 > --- a/test/tarantool-debugger-tests/debug-extension-tests.py > +++ b/test/tarantool-debugger-tests/debug-extension-tests.py > @@ -186,16 +186,30 @@ class TestLJGC(TestCaseBase): > ) > > > -class TestLJStack(TestCaseBase): > +STACK_RX = ( > + r'-+ Redzone:\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 TestLJStackBase(TestCaseBase): > extension_cmds = 'lj-stack' > location = 'lj_cf_print' > lua_script = 'print(1)' > - pattern = ( > - r'-+ Redzone:\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' > + pattern = STACK_RX > + > + > +# Check LLDB correctness for the specific stack. > +class TestLJStackFunc(TestCaseBase): > + extension_cmds = 'lj-stack' > + location = 'lj_cf_print' > + lua_script = ( > + 'local function nop() end\n' > + 'print()\n' > ) > + pattern = STACK_RX > > > class TestLJTV(TestCaseBase): --------------nL905PWFZeJCLlOTJuyG0OOR Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit

Hi, Sergey,

thanks for the patch! LGTM

On 6/4/26 12:30, Sergey Kaplun wrote:
This commit is the follow-up for the commit
593fef813b7d36060e0c1b1ae2df0fbc0d604d1f ("lldb: refactor extension").
`GetValueForExpressionPath()` may produce the empty value for negative
indexes. This leads to incorrect frame unwinding in the LLDB extension
and errors like:
| Failed to execute command `lj-stack`:
| 'Q' format requires 0 <= number <= 18446744073709551615

This patch adds special handling for the negative indices.
---
 src/luajit_dbg.py                             | 49 ++++++++++++++++---
 .../debug-extension-tests.py                  | 26 +++++++---
 2 files changed, 62 insertions(+), 13 deletions(-)

diff --git a/src/luajit_dbg.py b/src/luajit_dbg.py
index d9196f06..410f0191 100644
--- a/src/luajit_dbg.py
+++ b/src/luajit_dbg.py
@@ -255,15 +255,31 @@ class _GDBDebugger(Debugger):
 
 class _LLDBDebugger(Debugger):
     def _lldb_tp_isfp(self, tp):
-        return tp.GetBasicType() in [
+        return tp.GetCanonicalType().GetBasicType() in [
             lldb.eBasicTypeFloat,
             lldb.eBasicTypeDouble,
             lldb.eBasicTypeLongDouble
         ]
 
+    def _lldb_tp_issigned(self, tp):
+        return tp.GetCanonicalType().GetBasicType() in [
+            lldb.eBasicTypeChar,
+            lldb.eBasicTypeSignedChar,
+            lldb.eBasicTypeShort,
+            lldb.eBasicTypeInt,
+            lldb.eBasicTypeLong,
+            lldb.eBasicTypeLongLong,
+            lldb.eBasicTypeInt128
+        ]
+
     def _lldb_value_from_raw(self, raw_value, size, tp):
         isfp = self._lldb_tp_isfp(tp)
-        pack_flag = '<d' if isfp else '<Q'
+        if isfp:
+            pack_flag = '<d'
+        elif self._lldb_tp_issigned(tp):
+            pack_flag = '<q'
+        else:
+            pack_flag = '<Q'
         raw_data = struct.pack(pack_flag, raw_value)
         sbdata = lldb.SBData()
         sbdata.SetData(
@@ -308,9 +324,24 @@ class _LLDBDebugger(Debugger):
                 key = int(key)
             if type(key) is int:
                 # Allow array access.
-                return lldb.value(
-                    lldbval.sbvalue.GetValueForExpressionPath('[%i]' % key)
-                )
+                if key >= 0:
+                    return lldb.value(
+                        lldbval.sbvalue.GetValueForExpressionPath('[%i]' % key)
+                    )
+                else:
+                    # GetValueForExpressionPath doesn't work for
+                    # negative offsets.
+                    sbvalue = lldbval.sbvalue
+                    assert sbvalue.TypeIsPointerType(), \
+                        'attempt to get index of non-pointer type'
+                    tp = sbvalue.GetType().GetPointeeType()
+                    sz = sbvalue.deref.size
+                    addr = sbvalue.GetValueAsUnsigned() + key * sz
+                    return lldb.value(self.target.CreateValueFromAddress(
+                            '({tp}){addr}'.format(tp=tp, addr=addr),
+                            lldb.SBAddress(addr, self.target),
+                            tp,
+                    ))
             elif type(key) is str:
                 return lldb.value(lldbval.sbvalue.GetChildMemberWithName(key))
             raise Exception(TypeError('No item of type %s' % str(type(key))))
@@ -417,8 +448,12 @@ class _LLDBDebugger(Debugger):
         # may take the 8 bytes of memory instead of 4, before the
         # cast. Construct the value on the fly.
         tp = self._dbgtype(typestr)
-        is_fp = self._lldb_tp_isfp(tp)
-        rawval = float(val.GetValue()) if is_fp else val.GetValueAsUnsigned()
+        if self._lldb_tp_isfp(tp):
+            rawval = float(val.GetValue())
+        elif self._lldb_tp_issigned(tp):
+            rawval = val.GetValueAsSigned()
+        else:
+            rawval = val.GetValueAsUnsigned()
         return self._lldb_value_from_raw(rawval, val.GetByteSize(), tp)
 
     def sizeof(self, typestr):
diff --git a/test/tarantool-debugger-tests/debug-extension-tests.py b/test/tarantool-debugger-tests/debug-extension-tests.py
index 61529561..7cb60d84 100644
--- a/test/tarantool-debugger-tests/debug-extension-tests.py
+++ b/test/tarantool-debugger-tests/debug-extension-tests.py
@@ -186,16 +186,30 @@ class TestLJGC(TestCaseBase):
     )
 
 
-class TestLJStack(TestCaseBase):
+STACK_RX = (
+    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 TestLJStackBase(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'
+    pattern = STACK_RX
+
+
+# Check LLDB correctness for the specific stack.
+class TestLJStackFunc(TestCaseBase):
+    extension_cmds = 'lj-stack'
+    location = 'lj_cf_print'
+    lua_script = (
+        'local function nop() end\n'
+        'print()\n'
     )
+    pattern = STACK_RX
 
 
 class TestLJTV(TestCaseBase):
--------------nL905PWFZeJCLlOTJuyG0OOR--