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 9152E6AF4E; Sat, 23 Jul 2022 09:33:10 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 9152E6AF4E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1658557990; bh=ECOxtHf2MY6namxV3aBW6jFH+hQ1nTz6HE2Hmch1hgs=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=q1/IL9OH3hrtNW1dXe2n3v5ZuphU8M+Ahysrj7k34l2ozHmPV++GyNqHYoYr0J+V7 n1oj+mafIEy5Lvk6G6rUPexR9euw50bA8OrQJL0S1IKOL8WYTvec7q4Aog4BWwRmRS kVNSYe7SWZdYmS/GHl8Pb5fQxm4t2cCGf/AMdalk= Received: from mail-lf1-f48.google.com (mail-lf1-f48.google.com [209.85.167.48]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 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 1272A6ECE4 for ; Sat, 23 Jul 2022 03:11:55 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 1272A6ECE4 Received: by mail-lf1-f48.google.com with SMTP id t22so3584677lfg.1 for ; Fri, 22 Jul 2022 17:11:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+hkbFSM1E6XTz/nsyj2kSdEbJiTK6hH+BgVYkJWgjE0=; b=eude34W0hc2+AenCkkPVeG/hnEjMC3UGTb8TXsI5Scva73GbWr8tDQlhxyHwJYvlTz kdf8G6k5BP/bUGbLu8gXZwlAxbAx7vIgq+KP8KSENbL0UdXiLXcTejlfwZg0qwUYBRpu +5LM9sC5LWeSXkqP0TkH6pptVs4jl4CBobX+DQdVNO87XGr/X6HCpvMaUukpU1h+v0na zE05L5+nyDUTlI8DdtnVJhRV/9G0sQbHOBYrJJ/6A9ohLWxMaKGK1ama9BJDBfNkwNKc WFVIR4j0v+R+cbbUe/2Kpo1wO48HdVh8Jo/mQErc3EEFbepA+uQ5J56gZSfmyHKiDs4A Bzfw== X-Gm-Message-State: AJIora8AdCAdJ9ZCghEOEi0iyZwRVMPh4FQDrdM+lGHf84Z5+K4cKIEu UVGfBlAYXo9s89m9Uio/mXGPlcTMo6ibFw== X-Google-Smtp-Source: AGRyM1uvuesl28OC5txDG/O3hbmRPitQ5KRrfL0veWejI5QVsTDm13RCl3jwp8r0fTrOzGjFqBCn1A== X-Received: by 2002:a05:6512:695:b0:487:cc8c:7520 with SMTP id t21-20020a056512069500b00487cc8c7520mr865431lfe.522.1658535114302; Fri, 22 Jul 2022 17:11:54 -0700 (PDT) Received: from m1book8749.mail.msk ([178.176.77.142]) by smtp.gmail.com with ESMTPSA id f2-20020a056512360200b004870ef4a0c7sm1338115lfs.17.2022.07.22.17.11.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Jul 2022 17:11:53 -0700 (PDT) X-Google-Original-From: Mikhail Elhimov To: tarantool-patches@dev.tarantool.org Cc: Mikhail Elhimov Date: Sat, 23 Jul 2022 03:11:20 +0300 Message-Id: <2cb4fea69537ffd196d535a7d3d47c0511b0ecac.1658531255.git.m.elhimov@vk.team> X-Mailer: git-send-email 2.34.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailman-Approved-At: Sat, 23 Jul 2022 09:33:06 +0300 Subject: [Tarantool-patches] [PATCH 2/2] gdb: refactor iteration over frames while dumping stack 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: Mikhail Elhimov via Tarantool-patches Reply-To: Mikhail Elhimov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" Changes: - Introduce generator to iterate over frames in a Python way - Dump framelink of the bottom frame in a common way and identify it as a dummy framelink only inside of common dump function - Framelink always refers to the slot right before frame's base - Introduce constant LJ_FRAMELINK_NUM_SLOTS to make slot arithmetic more obvious. Previous using of boolean LJ_RT2 in arithmetic looked like a tricky way, both to read and maintain (however places where LJ_RT2 approach had been originally replicated from the source code are left intact, because it is expected that maintenance efforts for them will be minimal) --- src/luajit-gdb.py | 101 ++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/src/luajit-gdb.py b/src/luajit-gdb.py index 1e9a96fb..d7d34c70 100644 --- a/src/luajit-gdb.py +++ b/src/luajit-gdb.py @@ -158,6 +158,7 @@ LJ_64 = None LJ_GC64 = None LJ_FR2 = None LJ_DUALNUM = None +LJ_FRAMELINK_NUM_SLOTS = None LJ_GCVMASK = ((1 << 47) - 1) LJ_TISNUM = None @@ -299,6 +300,21 @@ gclen = { 'mmudata': gcringlen, } +def get_framelink_sentinel(L): + stack = mref('TValue *', L['stack']) + return stack + LJ_FRAMELINK_NUM_SLOTS - 1 + +# Generator that implements frame iterator +# every frame is represented as a tuple of framelink and frametop +def frames(L): + frametop = L['top'] + framelink = L['base'] - 1 + framelink_sentinel = get_framelink_sentinel(L) + while framelink is not None: + yield framelink, frametop + frametop = framelink - LJ_FRAMELINK_NUM_SLOTS + framelink = frame_prev(framelink) if framelink > framelink_sentinel else None + # Dumpers {{{ def dump_lj_tnil(tv): @@ -397,32 +413,38 @@ dumpers = { def dump_tvalue(tvalue): return dumpers.get(typenames(itypemap(tvalue)), dump_lj_invalid)(tvalue) +def dump_framelink_slot_address(fr): + return '{}:{}'.format(fr - 1, fr) if LJ_FR2 else '{}'.format(fr) + PADDING + +def dump_framelink_func(fr): + return dump_lj_tfunc(fr - 1 if LJ_FR2 else fr) + def dump_framelink(L, fr): - fr2 = fr + LJ_FR2 - - return '{fr}{padding} [ ] FRAME: [{pp}] delta={d}, {f}\n'.format( - fr = fr, - padding = ':{fr2}'.format(fr2 = fr2) if LJ_FR2 else PADDING, - pp = 'PP' if frame_ispcall(fr2) else '{frname}{p}'.format( - frname = frametypes(int(frame_type(fr2))), - p = 'P' if frame_typep(fr2) & FRAME_P else '' + if fr == get_framelink_sentinel(L): + return '{addr} [S ] FRAME: dummy L'.format( + addr = dump_framelink_slot_address(fr), + ) + return '{addr} [ ] FRAME: [{pp}] delta={d}, {f}'.format( + addr = dump_framelink_slot_address(fr), + pp = 'PP' if frame_ispcall(fr) else '{frname}{p}'.format( + frname = frametypes(int(frame_type(fr))), + p = 'P' if frame_typep(fr) & FRAME_P else '' ), - d = cast('TValue *', fr2) - cast('TValue *', frame_prev(fr2)), - f = dump_lj_tfunc(fr), + d = cast('TValue *', fr) - cast('TValue *', frame_prev(fr)), + f = dump_framelink_func(fr), ) -def dump_stack_slot(L, slot, base=None, top=None, eol='\n'): +def dump_stack_slot(L, slot, base=None, top=None): base = base or L['base'] top = top or L['top'] - return '{addr}{padding} [ {B}{T}{M}] VALUE: {value}{eol}'.format( + return '{addr}{padding} [ {B}{T}{M}] VALUE: {value}'.format( addr = strx64(slot), padding = PADDING, B = 'B' if slot == base else ' ', T = 'T' if slot == top else ' ', M = 'M' if slot == mref('TValue *', L['maxstack']) else ' ', value = dump_tvalue(slot), - eol = eol, ) def dump_stack(L, base=None, top=None): @@ -438,7 +460,7 @@ def dump_stack(L, base=None, top=None): nredslots = red, )) dump.extend([ - dump_stack_slot(L, maxstack + offset, base, top, '') + dump_stack_slot(L, maxstack + offset, base, top) for offset in range(red, 0, -1) ]) dump.extend([ @@ -446,50 +468,24 @@ def dump_stack(L, base=None, top=None): padding = '-' * len(PADDING), nstackslots = int((tou64(maxstack) - tou64(stack)) >> 3), ), - dump_stack_slot(L, maxstack, base, top, ''), + dump_stack_slot(L, maxstack, base, top), '{start}:{end} [ ] {nfreeslots} slots: Free stack slots'.format( start = strx64(top + 1), end = strx64(maxstack - 1), nfreeslots = int((tou64(maxstack) - tou64(top) - 8) >> 3), ), ]) - dump = '\n'.join(dump) + '\n' - - slot = top - framelink = base - (1 + LJ_FR2) - - # XXX: Lua stack unwinding algorithm consists of the following steps: - # 1. dump all data slots in the (framelink, top) interval - # 2. check whether there are remaining frames - # 3. if there are no slots further, stop the unwinding loop - # 4. otherwise, resolve the next framelink and top and go to (1) - # - # Postcondition (i.e. do-while) loops is the most fitting idiom for such - # case, but Python doesn't provide such lexical construction. Hence step (1) - # is unrolled for the topmost stack frame. - while slot > framelink + LJ_FR2: - dump += dump_stack_slot(L, slot, base, top) - slot -= 1 - - while framelink > stack: - assert slot == framelink + LJ_FR2, "Invalid slot during frame unwind" - dump += dump_framelink(L, framelink) - framelink = frame_prev(framelink + LJ_FR2) - LJ_FR2 - slot -= 1 + LJ_FR2 - while slot > framelink + LJ_FR2: - dump += dump_stack_slot(L, slot, base, top) - slot -= 1 - - assert slot == framelink + LJ_FR2, "Invalid slot after frame unwind" - # Skip a nil slot for the last frame for 2-slot frames. - slot -= LJ_FR2 - - dump += '{fr}{padding} [S ] FRAME: dummy L'.format( - fr = slot, - padding = ':{nilslot}'.format(nilslot = slot + 1) if LJ_FR2 else PADDING - ) - return dump + for framelink, frametop in frames(L): + # dump all data slots in the (framelink, top) interval + dump.extend([ + dump_stack_slot(L, framelink + offset, base, top) + for offset in range(frametop - framelink, 0, -1) + ]) + # dump frame slot (2 slots in case of GC64) + dump.append( dump_framelink(L, framelink) ) + + return '\n'.join(dump) def dump_gc(g): gc = g['gc'] @@ -717,7 +713,7 @@ The command requires no args and dumps current GC stats: )) def init(commands): - global LJ_64, LJ_GC64, LJ_FR2, LJ_DUALNUM, LJ_TISNUM, PADDING + global LJ_64, LJ_GC64, LJ_FR2, LJ_DUALNUM, LJ_FRAMELINK_NUM_SLOTS, LJ_TISNUM, PADDING # XXX Fragile: though connecting the callback looks like a crap but it # respects both Python 2 and Python 3 (see #4828). @@ -759,6 +755,7 @@ def init(commands): LJ_64 = str(gdb.parse_and_eval('IRT_PTR')) == 'IRT_P64' LJ_FR2 = LJ_GC64 = str(gdb.parse_and_eval('IRT_PGC')) == 'IRT_P64' LJ_DUALNUM = gdb.lookup_global_symbol('lj_lib_checknumber') is not None + LJ_FRAMELINK_NUM_SLOTS = 2 if LJ_FR2 else 1 except: gdb.write('luajit-gdb.py failed to load: ' 'no debugging symbols found for libluajit\n') -- 2.34.1