Package: python-gdb-ctrl
python-gdb-ctrlis a thin interface on top ofGDB, the debugger of the GNU Project.It will let you to spawn and control the debugger from a Python console
or program.python-gdb-ctrlhas two use modes: asynchronous and synchronous.The former is intended to be used by another application, the latter is
more a toy-example but handy while experimenting from a Python console.GDBCtrl- Asynchronous interfaceThe classGDBCtrlis suitable from integratingpython-gdb-ctrland the debugger with an UI or other event-based software.It has the basic primitives: -spawn: to run the debugger -shutdown: to quit or kill the debugger -send: to send GDB
commands -recv: to receive GDB recordsAll of them arecoroutinesthat can be integrated in anasyncioloop.Note: due limitations in one of the dependencies ofpython-gdb-ctrlall the primitives exceptrecvmay block as
they are not full asynchronous.SyncGDBCtrl- Synchronous interfaceWhileGDBCtrlis the class that you should use in a program, it is
much easier to play interactively withSyncGDBCtrl.>>>fromgdb_ctrlimportSyncGDBCtrl>>>gdb=SyncGDBCtrl(force_styling=None)Thespawnandshutdownmethods now are normal methods (they are
not coroutines)>>>gdb.spawn()The same applies forsendandrecv>>>gdb.send('file example/glad')'<token>'However a synchronousrecvis tricky because GDB may return several
records for a givensendso you need to know beforehand how many
times you need to callrecv:>>>gdb.recv(){'type':'Log','value':'file example/glad\n'}>>>gdb.recv(){'type':'Console','value':'Reading symbols from example/glad...'}>>>gdb.recv(){'type':'Console','value':'done.\n'}>>>gdb.recv()# byexample: +paste{'class':'done','token':<token>,'type':'Result'}>>>gdb.recv()'(gdb)'Notice how thesendreturned a<token>: you can use this to pair
the command with its result.Unfortunately this works only for the results, other GDB responses will
not have this token so you cannot know if theLogresponse above is
the product of the execution offile example/glador it is the
product of other command.Using the synchronousrecvis annoying: you need to know how many
responses you will receive.SyncGDBCtrlis mostly for interactive session so it provides handyexecutemethod to send a command and receive the records in one shot
taking care of retrieving all the responses.This is specially useful for certain commands that they do more than one
thing.Thestartcommand is an example of this:>>>gdb.execute('start')Temporarybreakpoint1<...>:fileglad.c,line52.Notify:{'bkpt':{'addr':'<...>','disp':'del','enabled':'y','file':'glad.c','fullname':'<...>/example/glad.c','func':'main','line':'52',<...>'times':'0','type':'breakpoint'}}Startingprogram:/home/user/proj/python-gdb-ctrl/example/glad<...>RunningExec:{'thread-id':'all'}<...>Notify:{'bkpts':[{'addr':'<...>','disp':'del','enabled':'y','file':'glad.c','fullname':'<...>/example/glad.c','func':'main','line':'52','number':'1','original-location':'main','thread-groups':['i1'],'times':'1','type':'breakpoint'}]}<...>Temporarybreakpoint1,main(argc=1,argv=0x<...>)atglad.c:5252pthread_create(&th,NULL,release_neurotoxins,NULL);Exec:{'bkptno':'1',<...>'reason':'breakpoint-hit','stopped-threads':'all','thread-id':'1'}<...>That’s a lot! When GDB executesstart, it sets a temporal breakpoint
in themainfunction, it runs the binary and it notifies us when the
breakpoint is hit and the program is stopped.That generates a lot of messages (in fact I omitted several ones).For convenience,execute()will print what it receives so you don’t
need to parse anything.If you want to useSyncGDBCtrlprogrammatically you can but I would
recommend against it and useGDBCtrlinstead.A pythonic interfaceBesidesexecute(),SyncGDBCtrlcan beextendedwith several
methods that will call a GDB command in apythonicway:>>>gdb.extend_interface_with_gdb_commands()Now instead of callingexecute('list')you can calllistdirectly.>>>gdb.list()47return0;48}4950intmain(intargc,char*argv[]){51pthread_tth;52pthread_create(&th,NULL,release_neurotoxins,NULL);5354intcores[CORES]={1};5556for(inti=1;i<argc;++i){DoneThe beauty of this is that you can request the documentation from a
Python shell:>>>print(gdb.list.__doc__)<...>Listspecifiedfunctionorline.Withnoargument,liststenmorelinesafteroraroundpreviouslisting."list -"liststhetenlinesbeforeapreviousten-linelisting.Oneargumentspecifiesaline,andtenlinesarelistedaroundthatline.Twoargumentswithcommabetweenspecifystartingandendinglinestolist.Linescanbespecifiedintheseways:LINENUM,tolistaroundthatlineincurrentfile,FILE:LINENUM,tolistaroundthatlineinthatfile,FUNCTION,tolistaroundbeginningofthatfunction,FILE:FUNCTION,todistinguishamonglike-namedstaticfunctions.*ADDRESS,tolistaroundthelinecontainingthataddress.Withtwoargs,ifoneisempty,itstandsfortenlinesawayfromtheotherarg.<...>Note:GDBcommandsthathaveaninvalidnameforPythonwillbeprefixedwitha``z``Finally, don’t forget to shutdown the debugger:>>>gdb.shutdown()# byexample: +pass -skipInstallJust run:$ pip install python-gdb-ctrl         # byexample: +passYou will find thepython-gdb-ctrlpackage atPyPIHacking/ContributingGo ahead! Clone the repository, do a small fix/enhancement, runmakedeps-devto install the development dependencies including the
test enginebyexample, then runmake testto ensure that everything is working as expected and
finally propose your Pull Request!