classification
Title: gdbinit lineno result is one line in excess
Type: behavior Stage: patch review
Components: Demos and Tools Versions: Python 3.2
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: amaury.forgeotdarc, georg.brandl, qpatata
Priority: normal Keywords:

Created on 2010-09-22 10:34 by qpatata, last changed 2010-11-03 07:41 by georg.brandl. This issue is now closed.

Messages (10)
msg117133 - (view) Author: (qpatata) Date: 2010-09-22 10:34
Thanks a lot to all python teams for your excel.lent work.

When latest version of gdbinit macros is used to debug with gdb a python 2.4 session, the result from lineno macro seems one line more than the correct one.

If we compare the gdb macro:

define lineno
    set $__continue = 1
    set $__co = f->f_code
    set $__lasti = f->f_lasti
    set $__sz = ((PyStringObject *)$__co->co_lnotab)->ob_size/2
    set $__p = (unsigned char *)((PyStringObject *)$__co->co_lnotab)->ob_sval
    set $__li = $__co->co_firstlineno
    set $__ad = 0
    while ($__sz-1 >= 0 && $__continue)
      set $__sz = $__sz - 1
      set $__ad = $__ad + *$__p
      set $__p = $__p + 1
      if ($__ad > $__lasti)
	set $__continue = 0
      end
      set $__li = $__li + *$__p
      set $__p = $__p + 1
    end
    printf "%d", $__li
end

with the related C source code in libpython.py

    def addr2line(self, addrq):
        '''
        Get the line number for a given bytecode offset

        Analogous to PyCode_Addr2Line; translated from pseudocode in
        Objects/lnotab_notes.txt
        '''
        co_lnotab = self.pyop_field('co_lnotab').proxyval(set())

        # Initialize lineno to co_firstlineno as per PyCode_Addr2Line
        # not 0, as lnotab_notes.txt has it:
        lineno = int_from_int(self.field('co_firstlineno'))

        addr = 0
        for addr_incr, line_incr in zip(co_lnotab[::2], co_lnotab[1::2]):
            addr += ord(addr_incr)
            if addr > addrq:
                return lineno
            lineno += ord(line_incr)
        return lineno

we see that if addr  is greater than addrq, the python codes returns immedialty, but the gdb macro adds a new delta of lines before exit the loop.

Kind regards.
msg117148 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2010-09-22 18:12
Can you show an example which shows an incorrect lineno?
msg117152 - (view) Author: (qpatata) Date: 2010-09-22 20:44
Hello,

Thanks for your colaboration.

Starting by the following python file, called "prueba.py":

> cat prueba.py
import time

def bar():
    time.sleep(10);
    print "hello";

def foo():
  while True:
    bar();

foo();




Open a gdb session with python2-6 as target:

> gdb /usr/bin/python2.6

and run the python program. 

gdb> run prueba.py

After a few seconds, type Ctrl-C to break the program. Usually, break will interrupt it when execution is in the "sleep" statement. A "bt" gives:

#0  0xb7fe2424 in __kernel_vsyscall ()
#1  0xb7d42fdd in select () from /lib/i686/cmov/libc.so.6
#2  0x08119a3f in floatsleep (self=0x0, args=(10,)) at ../Modules/timemodule.c:918
#3  time_sleep (self=0x0, args=(10,)) at ../Modules/timemodule.c:206
#4  0x080e0721 in call_function (f=Frame 0x82e17ac, for file prueba.py, line 4, in bar (), 
    throwflag=0) at ../Python/ceval.c:3750
#5  PyEval_EvalFrameEx (f=Frame 0x82e17ac, for file prueba.py, line 4, in bar (), throwflag=0)
    at ../Python/ceval.c:2412
...

If we go until C frame #5 (up, up, ...) and execute the lineno macro:

#5  PyEval_EvalFrameEx (f=Frame 0x82e17ac, for file prueba.py, line 4, in bar (), throwflag=0)
    at ../Python/ceval.c:2412
2412    in ../Python/ceval.c

(gdb) lineno
5
(gdb) 

It is clear the mismatch between the line reported by lineno (5), the one in the source file (4) and the one displayed by gdb (4).

In addition, if we look at the version history of the "gdbinit" file, we can see how version 39276 has an implementation of lineno who matches the related C code in Python project, but next version (39492) introduces a boolean to control the end of loop. This change is, probably, the origen of the mismatch.

Thanks a lot.
msg117158 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2010-09-22 22:11
OK, I reproduce the issue. It is now clear to me as well that r39492 was slightly wrong: the replacement of "break" should avoid to execute the end of the loop.

The following patch fixes the issue for me, can someone with better gdb knowledge check it?

Index: Misc/gdbinit
===================================================================
--- Misc/gdbinit        (revision 84966)
+++ Misc/gdbinit        (working copy)
@@ -59,9 +59,10 @@
       set $__p = $__p + 1
       if ($__ad > $__lasti)
        set $__continue = 0
+      else
+        set $__li = $__li + *$__p
+        set $__p = $__p + 1
       end
-      set $__li = $__li + *$__p
-      set $__p = $__p + 1
     end
     printf "%d", $__li
 end
msg117173 - (view) Author: (qpatata) Date: 2010-09-23 07:45
Well, me also I'm not expert in gdb.

Solution looks nice and previous testcase now gives the correct answer.

Thanks a lot for your help.
msg119285 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2010-10-21 12:59
Patch looks good, committed in r85768.
msg120119 - (view) Author: (qpatata) Date: 2010-11-01 11:10
Hi,

Thanks for the fix.

I'm wondering if it is valid to add a "\n" in the "lineno" print. This macro is called by other ones, like pyframe, that have their own format specifiers.

Kind regards.
msg120120 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2010-11-01 12:12
If you look at the commit, you'll see that I already added that newline.  Thanks anyway :)
msg120234 - (view) Author: (qpatata) Date: 2010-11-02 15:42
I'm sorry, I've not explained correctly.

I'm wondering if the addition of the \n is ok or not, taken into account that it breaks the format of the "pyframe" macro output. It could be better to keep the older version (without the \n").

Kind regards.
msg120311 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2010-11-03 07:41
Right. Fixed in r86134. Thanks :)
History
Date User Action Args
2010-11-03 07:41:12georg.brandlsetmessages: + msg120311
2010-11-02 15:42:56qpatatasetmessages: + msg120234
2010-11-01 12:12:10georg.brandlsetmessages: + msg120120
2010-11-01 11:10:54qpatatasetmessages: + msg120119
2010-10-21 12:59:33georg.brandlsetstatus: open -> closed

nosy: + georg.brandl
messages: + msg119285

resolution: fixed
2010-09-23 15:52:18belopolskysetcomponents: + Demos and Tools
versions: + Python 3.2, - Python 2.5
2010-09-23 07:45:40qpatatasetmessages: + msg117173
2010-09-22 22:11:04amaury.forgeotdarcsetmessages: + msg117158
stage: patch review
2010-09-22 20:44:21qpatatasetmessages: + msg117152
2010-09-22 18:12:53amaury.forgeotdarcsetnosy: + amaury.forgeotdarc
messages: + msg117148
2010-09-22 10:34:34qpatatacreate