Skip to content

Commit ad1d444

Browse files
igormunkinkyukhin
authored andcommitted
gdb: fix the extension to be loaded with Python 2
There was a mystic error when the extension was loaded by the old gdb versions built against Python 2: | (gdb) source luajit-gdb.py | Traceback (most recent call last): | File "luajit-gdb.py", line 702, in <module> | load(None) | File "luajit-gdb.py", line 699, in load | 'lj-gc': LJGC, | File "luajit-gdb.py", line 687, in init | command(name) | File "luajit-gdb.py", line 468, in __init__ | gdb.write('{} command initialized\n'.format(name)) | ValueError: sequence.index(x): x not in sequence I made a little investigation (for more info see the mentioned issue) and found the next fun fact: the exception was raised much earlier to <str.format>, more precisely in <gdb.events.new_objfile.disconnect>. However, the handled exception is preserved until <str.format> call and hits the condition underneath leading to the extension load failure. As a result to avoid the exception, the special global variable is introduced for legacy (i.e. Python 2) environment. It checks whether any callback is associated with new_objfile event prior to disconnecting it. This variable usage is encapsulated within two introduced routines: <connect> and <disconnect> which are wrappers for ones provided by gdb. Furthermore, after diving to gdb sources related to Python embedding, I found that callbacks are grouped into an internal list. Previous implementation appended the <load> function to this callback list on each its unsuccessful call, but only the successful one is removes it from the list. Thereby disconnect action is moved prior to connect one so there is no more than one <load> instance kept in callback list. Fixes tarantool/tarantool#4828 Reported-by: Oleg Babin <olegrok@tarantool.org> Reviewed-by: Oleg Babin <olegrok@tarantool.org> Reviewed-by: Sergey Ostanevich <sergos@tarantool.org> Signed-off-by: Igor Munkin <imun@tarantool.org>
1 parent 377198b commit ad1d444

File tree

1 file changed

+33
-7
lines changed

1 file changed

+33
-7
lines changed

src/luajit-gdb.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
# make script compatible with the ancient Python {{{
99

10-
if re.match(r'^2\.', sys.version):
10+
LEGACY = re.match(r'^2\.', sys.version)
11+
12+
if LEGACY:
13+
CONNECTED = False
1114
int = long
1215
range = xrange
1316

@@ -662,19 +665,42 @@ def invoke(self, arg, from_tty):
662665
def init(commands):
663666
global LJ_64, LJ_GC64, LJ_FR2
664667

668+
# XXX Fragile: though connecting the callback looks like a crap but it
669+
# respects both Python 2 and Python 3 (see #4828).
670+
def connect(callback):
671+
if LEGACY:
672+
global CONNECTED
673+
CONNECTED = True
674+
gdb.events.new_objfile.connect(callback)
675+
676+
# XXX Fragile: though disconnecting the callback looks like a crap but it
677+
# respects both Python 2 and Python 3 (see #4828).
678+
def disconnect(callback):
679+
if LEGACY:
680+
global CONNECTED
681+
if not CONNECTED:
682+
return
683+
CONNECTED = False
684+
gdb.events.new_objfile.disconnect(callback)
685+
686+
try:
687+
# Try to remove the callback at first to not append duplicates to
688+
# gdb.events.new_objfile internal list.
689+
disconnect(load)
690+
except:
691+
# Callback is not connected.
692+
pass
693+
665694
try:
695+
# Detect whether libluajit objfile is loaded.
666696
gdb.parse_and_eval('luaJIT_setmode')
667697
except:
668698
gdb.write('luajit-gdb.py initialization is postponed '
669699
'until libluajit objfile is loaded\n')
670-
gdb.events.new_objfile.connect(load)
700+
# Add a callback to be executed when the next objfile is loaded.
701+
connect(load)
671702
return
672703

673-
try:
674-
gdb.events.new_objfile.disconnect(load)
675-
except:
676-
pass # was not connected
677-
678704
try:
679705
LJ_64 = str(gdb.parse_and_eval('IRT_PTR')) == 'IRT_P64'
680706
LJ_FR2 = LJ_GC64 = str(gdb.parse_and_eval('IRT_PGC')) == 'IRT_P64'

0 commit comments

Comments
 (0)