PDB does not allow jumping to first statement?

C

Chris Lasher

Hi all,

I have a simple script:

---
#!/usr/bin/env python

a = 1
b = 2

c = a + b

print c
---

I launch said script with pdb:

python -m pdb simple.py

I noticed that I absolutely cannot jump back to the first statement
(line 3, "a = 1") using the jump command. I can jump to any other line
BUT the first statement's using the "jump <line number>" command. I
experience the same behavior with Winpdb and rpdb2. Why is this?

Stumped,
Chris
 
D

Duncan Booth

Chris Lasher said:
I noticed that I absolutely cannot jump back to the first statement
(line 3, "a = 1") using the jump command. I can jump to any other line
BUT the first statement's using the "jump <line number>" command. I
experience the same behavior with Winpdb and rpdb2. Why is this?

Which version of Python, and what happens when you try it?

It works fine for me with Python 2.5 on Windows:

C:\Temp>\python25\python -m pdb t.py
c:\temp\t.py(3)<module>()
-> a = 1
(Pdb) s
c:\temp\t.py(4)<module>()
-> b = 2
(Pdb) j 3
c:\temp\t.py(3)<module>()
-> a = 1
(Pdb)
 
P

Peter Otten

Duncan said:
Which version of Python, and what happens when you try it?

It works fine for me with Python 2.5 on Windows:

C:\Temp>\python25\python -m pdb t.py
-> a = 1
(Pdb) s
-> b = 2
(Pdb) j 3
-> a = 1
(Pdb)

It looks like you successfully jumped to the first line, but it will be
skipped if you try to execute it:

$ cat tmp.py
print "aaa"
print "bbb"
print "ccc"
print "ddd"
$ python2.5 -m pdb tmp.py
/home/nn/tmp.py(1)<module>()
-> print "aaa"
(Pdb) s
aaa
/home/nn/tmp.py(2)<module>()
-> print "bbb"
(Pdb) j 1
/home/nn/tmp.py(1)<module>()
-> print "aaa"
(Pdb) s
bbb <-- wrong
/home/nn/tmp.py(3)<module>()
-> print "ccc"
(Pdb) s
ccc
/home/nn/tmp.py(4)<module>()
-> print "ddd"
(Pdb) j 2
/home/nn/tmp.py(2)<module>()
-> print "bbb"
(Pdb) s
bbb <-- correct
/home/nn/tmp.py(3)<module>()
-> print "ccc"

Peter
 
D

Duncan Booth

Peter Otten said:
It looks like you successfully jumped to the first line, but it will be
skipped if you try to execute it:

That's why I asked what actually happened. Yes, you and the OP seem to
be correct, jumping to the first executable line in a module appears not
to execute the line.

I verified (with a print statement in pdb) that assigning to
self.curframe.f_lineno sets self.curframe.f_lineno and
sel.curframe.f_lasti incorrectly:

C:\Temp>\python25\python -m pdb t.py
c:\temp\t.py(3)<module>()
-> a = 1
(Pdb) s
c:\temp\t.py(4)<module>()
-> b = 2
(Pdb) s
c:\temp\t.py(5)<module>()
-> a = 3
(Pdb) l
1 #!/usr/bin/env python
2
3 a = 1
4 b = 2
5 -> a = 3
6 c = a + b
7 import dis, sys
8 dis.dis(sys._getframe().f_code)
9 print c
[EOF]
(Pdb) j 4
f_lineno 4 f_lasti 6
c:\temp\t.py(4)<module>()
-> b = 2
(Pdb) j 3
f_lineno 4 f_lasti 6
c:\temp\t.py(3)<module>()
-> a = 1
(Pdb) j 5
f_lineno 5 f_lasti 12
c:\temp\t.py(5)<module>()
-> a = 3
(Pdb) j 3
f_lineno 4 f_lasti 6
c:\temp\t.py(3)<module>()
-> a = 1
(Pdb)

The problem looks to be in frameobject.c:

addr = 0;
line = f->f_code->co_firstlineno;
new_lasti = -1;
for (offset = 0; offset < lnotab_len; offset += 2) {
addr += lnotab[offset];
line += lnotab[offset+1];
if (line >= new_lineno) {
new_lasti = addr;
new_lineno = line;
break;
}
}

The first bytes in lnotab are the length and line increment for line 3
(i.e. 6, 1). If line==f->f_code->co_firstlineno it should set new_lasti=
0, new_lineno=line but the loop still executes once which increments
new_lasti and new_lineno to the next line (6, 4).
 
R

rocky.bernstein

Hi all,

I have a simple script:

---
#!/usr/bin/envpython

a = 1
b = 2

c = a + b

print c
---

I launch said script withpdb:

python-mpdbsimple.py

I noticed that I absolutely cannot jump back to the first statement
(line 3, "a = 1") using the jump command. I can jump to any other line
BUT the first statement's using the "jump <line number>" command. I
experience the same behavior with Winpdb and rpdb2. Why is this?

Stumped,
Chris

I tried on GNU/Linux and Python versions 2.4 and 2.5 and get the same
behavior. Best as I can tell, it looks like a bug in Python. pdb,
pydb, rpdb2 all handle the "jump" command by changing the frame
f_lineno value. When the corresponding code pointer has offset 0 (or
equivalently and more simlply as you put it, is the first statement)
this doesn't seem to work properly. But this also implies that all you
need to do is add something as the first statement. A docstring
comment, e.g.
"this is what my program does..."
comes to mind :)

Lastly, I'll mention that I what most folks want to do is not jump to
the beginning of the program but rather *restart* it. The difference
here as applied to your example is seen in the way variables (e.g. a,
b, and c) are handled. In a "restart", those names would go back to
being undefined and referring to them before assigning to them would
cause a NameError exception. With "jump", they retain their existing
values.

In pydb (http://bashdb.sf.net/pydb) there are two variations of
restarting a program, one which preserves debugger state ("run") and
one which doesn't ("restart") as it is just a re-exec of the program.
In the presence of multiple threads the exec restart the only reliable
way I know of to force a restart.

Recently in Python's SVN the patch I submitted over a year ago was
applied, so if you prefer pdb and want the "run"-like restart, you can
use that.
 
C

Chris Lasher

I tried on GNU/Linux and Python versions 2.4 and 2.5 and get the same
behavior. Best as I can tell, it looks like a bug in Python. pdb,
pydb, rpdb2 all handle the "jump" command by changing the frame
f_lineno value. When the corresponding code pointer has offset 0 (or
equivalently and more simlply as you put it, is the first statement)
this doesn't seem to work properly. But this also implies that all you
need to do is add something as the first statement. A docstring
comment, e.g.
"this is what my program does..."
comes to mind :)

I started implementing this, but it's a hack. Looks like it's time for
me to file a bug report!
Lastly, I'll mention that I what most folks want to do is not jump to
the beginning of the program but rather *restart* it. The difference
here as applied to your example is seen in the way variables (e.g. a,
b, and c) are handled. In a "restart", those names would go back to
being undefined and referring to them before assigning to them would
cause a NameError exception. With "jump", they retain their existing
values.

In the case I was working with, I really did want to "jump" and retain
the values, rather than restart and clear those values.

Just as an aside, Rocky, I really like your ShowMeDo on pydb. Thanks
for making that. (For those who haven't seen it, check out the
"Introducing the pydb Debugger" at <http://showmedo.com/videos/Python>)
 
C

Chris Lasher

I have submitted this as a bug via SourceForge:
<https://sourceforge.net/tracker/?
func=detail&atid=105470&aid=1689458&group_id=5470>
or if munged
<http://tinyurl.com/2nwxsf>

The Python folks would like a test case and/or a patch. This is well
beyond my ken as a humble Python user. Could anybody more
knowledgeable please contribute one or both? Duncan or Rocky, would
you be able to spare time and effort?

Chris
 
R

rocky.bernstein

I have submitted this as a bug via SourceForge:
<https://sourceforge.net/tracker/?
func=detail&atid=105470&aid=1689458&group_id=5470>
or if munged
<http://tinyurl.com/2nwxsf>

ThePythonfolks would like a test case and/or a patch. This is well
beyond my ken as a humblePythonuser. Could anybody more
knowledgeable please contribute one or both? Duncan or Rocky, would
you be able to spare time and effort?

Chris

First and foremost, thanks for submitting the bug report!

Alas, I don't use Python much anymore in day-to-day activities. Ruby
rules! However some weekend (when I'm not doing work) I'll try to find
time to conjure up an example.

But here's a sketch of how I think a small test case would work. One
would use sys.settrace() to set up the mechanism to get the current
frame after each statement gets run. In the function, say bugcheck(),
which used as the hook given to sys.settrace(), if the caller's
f_lineno is not the first statement, one would set it to the first
statement noting that the reassignment has happened so we don't loop
indefinitely. Then one would return from the function which will let
the program do a step and check what value of f_lineno appears in the
subsequent calls of bugcheck().

Alternatively one could write a .pdbrc which basically issues the
"step" and "jump" commands and prints out the line number. (In pydb or
gdb the command to print the current line would be "info line"; in
pdb I'm not sure what the best command is - "list"?, "bt?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top