Skip to content

Commit

Permalink
gdb: fix dump stack without function frame
Browse files Browse the repository at this point in the history
Dummy frame is the "initial" coroutine state, when the framelink slot
(i.e. L->base - (1 + LJ_FR2)) is the bottom slot of the guest stack
(i.e. L->stack). Since coroutine stack unwinding is implemented via
precondition loop, lj-stack doesn't dump the slots for the dummy frame,
since the framelink points to the stack bottom.

The output looks like the following:

| 0x7fb512ac40:0x7fb512ac70 [    ] 7 slots: Red zone
| 0x7fb512ac38              [   M]
| 0x7fb512ab28:0x7fb512ac30 [    ] 34 slots: Free stack slots
| 0x7fb512ab20              [  T ]
| 0x7fb512ab08:0x7fb512ab10 [S   ] FRAME: dummy L

Python doesn't provide post-condition (do-while) syntax construction,
that fits better for this case, so the unwinding of the topmost frame is
just manually unrolled.

As a result of the patch the output looks like the following:

| 0x7fb512ac40:0x7fb512ac70 [    ] 7 slots: Red zone
| 0x7fb512ac38              [   M]
| 0x7fb512ab28:0x7fb512ac30 [    ] 34 slots: Free stack slots
| 0x7fb512ab20              [  T ]
| 0x7fb512ab18              [    ] VALUE: string 0 "/tmp/net_box.lua:6: err in ser" @ 0x7fb512ade8
| 0x7fb512ab10              [ B  ] VALUE: table @ 0x7fb512ac80 (asize: 0, hmask: 0x0)
| 0x7fb512ab00:0x7fb512ab08 [S   ] FRAME: dummy L

Reviewed-by: Igor Munkin <imun@tarantool.org>
Reviewed-by: Sergey Ostanevich <sergos@tarantool.org>
Signed-off-by: Igor Munkin <imun@tarantool.org>
  • Loading branch information
Buristan authored and igormunkin committed Jul 22, 2021
1 parent 77c4a07 commit 475359b
Showing 1 changed file with 21 additions and 3 deletions.
24 changes: 21 additions & 3 deletions src/luajit-gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,13 +427,31 @@ def dump_stack(L, base=None, top=None):
slot = top - 1
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 > mref('TValue *', L['stack']):
while slot > framelink + LJ_FR2:
dump += dump_stack_slot(L, slot, base, top)
slot -= 1
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,
Expand Down

0 comments on commit 475359b

Please sign in to comment.