Using less as gdb pager - gdb

I noticed that in GDB, when issuing commands with long output like info variables, the output is displayed one page at time, pressing enter to go down and q to quit.
Is it possible to replace the default pager with another one, such as less, so that I can navigate up and down, quitting, searching, etc?

Is it possible to replace the default pager with another one
No: GDB doesn't call into external program to display the output, it simply pauses the output every screenfull (and you can make it not pause by set height 0).
In addtion to running inside emacs, you could also use screen or tmux (learning them will generally help you in a lot of other situations), or ask GDB to log output (set logging on) and then search in gdb.txt with any $PAGER you want.

Starting with version 9.1, GDB has a pipe command, so you can send a command's output to the pager of your choice. From the documentation:
pipe [command] | shell_command
Executes command and sends its output to shell_command. Note that no space is needed around |. If no command is provided, the last command executed is repeated.

run gdb inside of emacs and you should be able to use emacs' paging commands.
run emacs
type M-x gdb return (M stands for meta - alt key or option on Macs)
The Emacs message bar will now display the message:
Run gdb (like this): gdb
More information is available here: http://tedlab.mit.edu/~dr/gdbintro.html
HTH

you can put the following user-defined commands in ~/.gdbinit, then
% cat ~/.gdbinit
python import os
define less1
python os.popen("less","w").write(gdb.execute("$arg0",to_string=True))
end
define less2
python os.popen("less","w").write(gdb.execute("$arg0 $arg1",to_string=True))
end
...
% gdb
(gdb) less2 info var
...
(gdb) less1 disass
...

It is a bit old thread, but I think it is worth to add. #yichun gave a very nice idea here, but to be more practical it can be extended to any number of arguments:
define less
python import os
python os.popen("less","w").write(gdb.execute(' '.join(["$arg{0}".format(i) for i in range(0, argc)]), to_string=True))
end
Then it can also woth adding exceptions handling and waiting for processes to terminate to avoid keyboard glitches and we have something like that:
% cat ~/.gdbinit
define less
python argc = $argc
python
import os
f = None
try:
f = os.popen("less","w")
f.write(gdb.execute(' '.join(["$arg{0}".format(i) for i in range(0, argc)]), to_string=True))
except Exception as e:
if f:
f.write(str(e))
else:
print (str(e))
finally:
if f:
f.close()
end
end

In gdb 8.1.1 this code in .gdbinit adds the required functionality:
python
import os
class Less(gdb.Command):
def __init__(self):
super().__init__("less", gdb.COMMAND_USER, gdb.COMPLETE_COMMAND)
def invoke(self, argstr, from_tty):
with os.popen("less","w") as pipe:
try:
pipe.write(gdb.execute(argstr, to_string=True))
except Exception as e:
pipe.write(str(e))
Less()
end
Usage
(gdb) less info breakpoints
(gdb) less backtrace
Information: Commands In Python.

Related

breakpoint at end of a function

I am trying to log the input and output of a function via gdb script. below is a sample script.
set logging on
b func2
commands
silent
bt 1
continue
end
b func1
commands
silent
bt 1
set logging off
continue
end
It works fine and breakpoints at the specified functions, prints the backtrace and continues.
is there a way to automatically set a breakpoint just before the called function returns to the calling function, so that I can just print output variables via gdb just after this "new" breakpoint.
This will greatly simplify my debug, and help understand the function behavior for different calls in the code.
Any help is highly appreciated.
Thanks a lot in advance !
I have looked into this and cannot find a way to do this with normal GDB breakpoints.
It is possible to implement using the GDB Python extensions API.
source-ing a file with the following content (source FILENAME) from with GDB will allow one to issue the command break-return which will place a temporary break-point at every 'return' in the current file (this is overkill but works). Once any one of the breakpoints is hit they are all deleted.
import gdb
class _ReturnBreakpoint(gdb.Breakpoint):
def stop(self):
for breakpoint in self._siblings:
if breakpoint.number != self.number:
gdb.execute(f"d {breakpoint.number}")
return True
class _BreakReturn(gdb.Command):
def __init__(self):
super(_BreakReturn, self).__init__("break-return", gdb.COMMAND_USER)
def invoke(self, arg, from_tty):
function_name = gdb.selected_frame().name()
source_file = gdb.selected_frame().find_sal().symtab.filename
breakpoints = []
with open(source_file) as o:
for zero_based_index, line in enumerate(o.readlines()):
if not 'return ' in line:
continue
breakpoint = _ReturnBreakpoint(line=zero_based_index+1, temporary=True)
breakpoints.append(breakpoint)
for breakpoint in breakpoints:
breakpoint._siblings = breakpoints
_BreakReturn() # register the command with GDB
Taken from https://github.com/jbcoe/GDB-extensions/blob/master/extensions/break-return.py
Patches are welcome.

gdb - perform a command n times

I am using the gdb debugger to run a program that has a loop in it (let's sat of 10).
When I get to the loop, I don't want to go into it. I know I can make a second breakpoint after the loop and than do c (continue). But I also remember there is a possibility to do something like n 10 (next 10 times). n 10 doesn't work (gdb doesn't say I've done something wrong, but it doesn't do what I am expecting).
Is it possible to run a command n times?
To perform any gdb command N times, the easiest way is:
(gdb) python [gdb.execute('YOUR_COMMAND') for x in range(N)]
It can be very helpful for your custom gdb commands (see gdb define)
For example,
(gdb) python [gdb.execute('next') for x in range(10)]
(gdb) python [gdb.execute('step') for x in range(5)]
Do you know the command until?
Try use it to go until line X.
Example:
(gdb) until 123
or
(gdb) u 123
(gdb) help until
Execute until the program reaches a source line
greater than the current or a specified location (same args as break
command) within the current frame.
GDB Python API
You can run a command n times with the GDB Python API if someone really needs it:
class RepeatCmd(gdb.Command):
"""
Repeat a command n times:
repeat-cmd <n> <cmd>
"""
def __init__(self):
super().__init__(
'repeat-cmd',
gdb.COMMAND_NONE,
gdb.COMPLETE_NONE,
False
)
def invoke(self, arg, from_tty):
args = gdb.string_to_argv(arg)
n = int(args[0])
cmd = ' '.join(args[1:])
for i in range(n):
gdb.execute(cmd)
RepeatCmd()
GitHub upstream.
For the use case, you may also be interested in continue <n>.

Debuggers not acting properly on Jupyter notebooks

I'm trying to debug some code in a Jupyter notebook. I've tried 3 4 different methods, and they all suffer from the same problem:
--Return--
None
> <ipython-input-22-04c6f5c205d1>(3)<module>()
1 import IPython.core.debugger as dbg
2 dber = dbg.Tracer()
----> 3 dber()
4 tst = huh.plot(ret_params=True)
5 type(tst)
ipdb> n
> y:\miniconda\lib\site-packages\ipython\core\interactiveshell.py(2884)run_code()
2882 finally:
2883 # Reset our crash handler in place
-> 2884 sys.excepthook = old_excepthook
2885 except SystemExit as e:
2886 if result is not None:
as you can see, the n command, which from what I understood from the pdb documentation should execute the next line (I'm assuming ipdb is just pdb adapted to work on IPython, especially since I can't find any command documentation that refers specifically to ipdb and not pdb)
s also has the same problem. This is actually what I want to do - step into the plot call (from what I understand, this is what s is supposed to do), but what I get is exactly the same as what I get from n. I also just tried r and I get the same problem.
Every example I've seen just uses Tracer()() or IPython.core.debugger.PDB().set_trace() to set a breakpoint in the line that follows the command, but both cause the same problems (and, I assume, are actually the exact same thing).
I also tried %debug (MultipleInstanceError) and %%debug (Doesn't show the code in the line being executed - just says what line, using s doesn't step into the function, just runs the line).
Edit: turns out, according to a blog post from April of this year, plain pdb should also work. It does allow me to interactively debug the notebook, but it only prints the current line being debugged (probably not a bug), and it has the same problem as IPython's set_trace() and Tracer()()
on plain IPython console, IPython's set_trace (only one I've tested) works just fine.
I encountered the same problem when debugging in Jupyter Notebook. What is working for me however, is when I call set_trace() inside a function. Why is explained here (click), though I don't really understand why others don't encounter this problem. Anyway, if you need a pragmatic solution for your problem and you want to debug a self-written function, try this:
from IPython.core.debugger import set_trace
def thisfunction(x):
set_trace() # start debugging when calling the function
x += 2
return x
thisfunction(5) # ipdb console opens and I can use 'n'
Now I can use 'n' and the debugging process runs the next line without problems. If I use the following code, however, I run into your above mentioned problem.
from IPython.core.debugger import set_trace
def thisfunction(x):
x += 2
return x
set_trace() # start debugging before calling the function.
# Calling 's' in the ipdb console to step inside "thisfunction" produces an error
thisfunction(5)
Hope this helps until somebody could solve the problem completely.

Prevent PLT (procedure linkage table) breakpoints in GDB

In recent versions of GDB, setting a breakpoint on a library function call results in multiple actual breakpoints:
Call into the procedure linkage table (PLT)
The actual function call
This means that when the library function is called, we end up going through two breaks each time. In previous GDB versions, only #2 would be created and hence you only get one break.
So the question is: can one can create a library function call breakpoint without the corresponding PLT breakpoint? I am aware that you can create a regular breakpoint and then explicitly disable the PLT one, but this is really tedious.
I think I found a solution for this problem. You can use the
break *address
syntax of break, but instead of specifying a hex address, you give the name of the function (which evaluates to the function's address). Something like
break *myfunction
That sets a breakpoint only on the main function, and not any of the PLT versions.
add these lines to your ~/.gdbinit file and call disaplts to disable all #plt breakpoints:
define disaplts
python
import gdb
from StringIO import StringIO
lines=gdb.execute("info break", True, True)
for l in StringIO(lines).readlines():
if "#plt" in l:
bp=l.split()[0]
gdb.execute("disa {0}".format(bp))
print("disabling {0}".format(bp))
end
end
# disable on library load
catch load mylibrarywithplt disaplt
Note: mind the spacing in python code. I recommend you use cat to paste the content.
EDIT: added "execute on library load" per #WallStProg
Yup, it can be done.
To simply place breakpoints on all functions, use command:
rbreak .*
So, this will place breakpoints on all the functions including PLT.
Now type:
save breakpoints filename
This will save a list of all breakpoints in a file called as filename.
Now open the file in normal text editor like gedit, and remove all the PLT lines given at the end of the file. And then save the file with only the required functions on which you want to place breakpoints.
or
Remove all the #plt from the function names using the command:
sed 's/#plt//g' filename > newfilename
After this, exit gdb (to unlink gdb from useless PLT breakpoints, added before) and execute gdb again.
Now type command:
source filename
or
source newfilename (in case you used sed command)
At this point, gdb will put breakpoints only on the functions mentioned in the file called as "filename" or "newfilename" (if used sed).
Note: To filter functions more in the file "filename", one can use grep also according to the requirements. :)
Here's a command, rdelete, that is like delete in the same way that rbreak is like break - it deletes breakpoints based on a regexp argument.
$ cat rdelete.py
import gdb
import re
class RDelete(gdb.Command):
"""Delete breakpoints for all locations matching REGEXP."""
def __init__(self):
super (RDelete, self).__init__ ("rdelete", gdb.COMMAND_BREAKPOINTS, gdb.COMPLETE_LOCATION)
def invoke(self, argstr, from_tty):
bppat = re.compile(argstr)
for bp in gdb.breakpoints():
if bppat.search(bp.location):
print("Deleting breakpoint {} at {}".format(bp.number, bp.location))
bp.delete()
RDelete()
$ gdb -q hoist
(gdb) rbreak .*
...
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000580 in main at hoist.c:6
2 breakpoint keep y 0x00000000000007a0 in x at hoist.c:4
3 breakpoint keep y 0x0000000000000530 <_init>
4 breakpoint keep y 0x0000000000000560 <printf#plt>
5 breakpoint keep y 0x00000000000007b0 <__libc_csu_init>
6 breakpoint keep y 0x0000000000000820 <__libc_csu_fini>
7 breakpoint keep y 0x0000000000000824 <_fini>
(gdb) source rdelete.py
(gdb) rdelete #plt
Deleting breakpoint 4 at printf#plt

How can I use GDB to get the length of an instruction?

The problem I am trying to solve is that I want to dynamically compute the length of an instruction given its address (from within GDB) and set that length as the value of a variable. The challenge is that I don't want any extraneous output printed to the console (e.g. disassembled instructions, etc.).
My normal approach to this is to do x/2i ADDR, then subtract the two addresses. I would like to achieve the same thing automatically; however, I don't want anything printed to the console. If I could disable console output then I would be able to do this by doing x/2i ADDR, followed by $_ - ADDR.
I have not found a way to disable the output of a command in GDB. If you know such a way then please tell me! However, I have discovered interpreter-exec and GDB/MI. A quick test shows that doing x/2i works on GDB/MI, and the value of $_ computed by the MI interpreter is shared with the console interpreter. Unfortunately, this approach also spits out a lot of output.
Does anyone know a way to either calculate the length of an instruction without displaying anything, or how to disable the output of interpreter-exec, thus allowing me to achieve my goal? Thank you.
I'll give an arguably cleaner and more extensible solution that's not really shorter. It implements $instn_length() as a new GDB convenience function.
Save this to instn-length.py
import gdb
def instn_length(addr_expr):
t = gdb.execute('x/2i ' + addr_expr, to_string=True)
return long(gdb.parse_and_eval('$_')) - long(gdb.parse_and_eval(addr_expr))
class InstnLength(gdb.Function):
def __init__(self):
super(InstnLength, self).__init__('instn_length')
def invoke(self, addr):
return instn_length(str(long(addr)))
InstnLength()
Then run
$ gdb -q -x instn-length.py /bin/true
Reading symbols from /usr/bin/true...Reading symbols from /usr/lib/debug/usr/bin/true.debug...done.
done.
(gdb) start
Temporary breakpoint 1 at 0x4014c0: file true.c, line 59.
Starting program: /usr/bin/true
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffde28) at true.c:59
59 if (argc == 2)
(gdb) p $instn_length($pc)
$1 = 3
(gdb) disassemble /r $pc, $pc + 4
Dump of assembler code from 0x4014c0 to 0x4014c4:
An alternative implementation of instn_length() is to use the gdb.Architecture.disassemble() method in GDB 7.6+:
def instn_length(addr_expr):
addr = long(gdb.parse_and_eval(addr_expr))
arch = gdb.selected_frame().architecture()
return arch.disassemble(addr)[0]['length']
I have found a suitable solution; however, shorter solutions would be preferred. This solution sets a logging file to /dev/null, sets to to be overridden if it exists, and then redirects the console output to the log file temporarily.
define get-in-length
set logging file /dev/null
set logging overwrite on
set logging redirect on
set logging on
x/2i $arg0
set logging off
set logging redirect off
set logging overwrite off
set $_in_length = ((unsigned long) $_) - ((unsigned long) $arg0)
end
This solution was heavily inspired by another question's answer: How to get my program name in GDB when writting a "define" script?.