Package: gdbplotlib
GDBplotlibGDBplotlib is an extension to GDB which enables easy visualisation and exporting of data structures. The current implementation is focused on C++, although it could theoretically be extended to work with any language supported by GDB.FeaturesMany different visualisations, such as line graphs, scatter plots and histogramsExporting of variables in.mat, Python pickle and binary formatsWorks for arbitrarily nested data structuresSlice supportCan be easily extended to work with any custom typeRequirementsGDB >= 7.0Python 3NumPyMatplotlibScipy (OPTIONAL - for exporting to.mat)InstallationGDBplotlib can be installed viapip:$pipinstallgdbplotlibTo make GDBplotlib available in GDB sessions, add the following lines to~/.gdbinit(or create it if it doesn't exist):python
importgdbplotlib
endUsage ExamplesConsider the following C++ program:#include<vector>#include<array>intmain(){std::array<double,6>x={0.1,0.9,0.8,0.7,0.2,0.1};int*y=newint[100];for(inti=0;i<100;++i){y[i]=50-i+int(5e-3*i*i);}std::vector<std::array<int*,10>>z(10);for(inti=0;i<z.size();++i){for(intj=0;j<z[i].size();++j){z[i][j]=newint[10];for(intk=0;k<10;++k){z[i][j][k]=i+2*j+3*k;}}}return0;}To create a line graph ofx, execute the command:plot xGDBplotlib has full support for Python-style slicing. For example, to plot only the first 3 elements, simply execute:plot x[:3]Pointers are an example of an unbounded type - that is a type for which it is not possible to deduce the number of elements. In order to correctly plot the variabley, the user must explicitily give an endpoint using the slice syntax:plot y[:100]Note that when slicing an unbounded type, negative start/end slice indices no longer refer to an index relative to the container's end (as in Python), but rather relative its start (as in C indexing).GDBplotlib supports data extraction of arbitrarily nested structures. For example, to create a 3D plot ofz, run:plot3d z[::-1,2,4:8]Supported Typesstd::vectorstd::arrayC-style arrayPointerAll integral and floating point typesstd::complex<float>andstd::complex<double>Supported Commandsplot VAR...- Create a 1D line plot ofVAR, whereVARis any 1D or 2D structureplot3d VAR- Create a 2D surface plot ofVAR, whereVARis a 2D real-valued structurescatter VAR...- Create a 2D scatter plot ofVAR, whereVARis either a 1D complex-valued structure, an N-by-2 real-valued structure, or two 1D real-valued structuresscatter3d VAR...- Create a 3D scatter plot ofVAR, whereVARis either an N-by-3 real-valued structure, or three 1D real-valued structureshist VAR...- Create a histogram plot ofVAR, whereVARis any 1D or 2D structurefft VAR...- Create a power spectral density plot ofVAR, whereVARis any 1D structuresave FILE VAR- SaveVARto the fileFILEin binary formatsavepy FILE VAR- SaveVARto the fileFILEin Python pickle formatsavemat FILE VAR...- SaveVARto the fileFILEin Matlab formatCustom TypesIt is easy to extend GDBplotlib to handle any desired type. Let's look at an example of how we might implement support forstd::vector:fromgdbplotlib.type_handlerimportTypeHandlerfromgdbplotlib.defaultimportdefaultclassStdVector(TypeHandler):@staticmethoddefcan_handle(gdb_type:gdb.Type)->bool:returnstr(gdb_type).startswith("std::vector")defshape(self,gdb_value:gdb.Value)->Tuple[Optional[int],...]:size=int(gdb_value["_M_impl"]["_M_finish"]-gdb_value["_M_impl"]["_M_start"])return(size,)defcontained_type(self,gdb_value:gdb.Value)->gdb.Type:returngdb_value.type.template_argument(0)defextract(self,gdb_value:gdb.Value,index:Tuple[int,...]):return(gdb_value["_M_impl"]["_M_start"]+index[0]).dereference()default.register(StdVector)To handle a custom type, we must create a class derived from the abstract base classgdbplotlib.TypeHandler. There are 4 methods that need to be overriden:can_handle- Given a type, determine whether this handler is able to handle it. For astd::vector, we want to handle any type whose name begins withstd::vectorshape- Given a value of our type, return the shape (in the NumPy sense) of the container as a tuple. The length of the tuple is equal to the number of dimensions of our type, and the values are size of the given dimension. If a given dimension has an unbounded size (as in the case of a pointer), that dimension should be given a value ofNone. Astd::vectoris 1-dimensional, with a size equal to the difference between the start and end pointers.contained_type- Given a value of our type, return the type of any contained elements. This is usually either a fixed type, or one of the type's template arguments. For astd::vector, it is the first template argument.extract- Given an index, extract an element from the container. Theindexparameter is ann-length tuple, wherenis the number of dimensions of the container. For astd::vector, we increment the start pointer by the first (and only) index, and dereference to get the value.Finally, we register our type handler with GDBplotlib so that it can be used with any command. Note that we register the class itself, not its instantiation.classFloat(ScalarTypeHandler):@staticmethoddefcan_handle(gdb_type:gdb.Type)->bool:returnstr(gdb_type)=="float"defextract(self,gdb_value:gdb.Value,index:Tuple[int,...]):returnnp.float32(gdb_value)Handling a custom scalar type is a similar process. The main difference is that we derive fromgdbplotlib.ScalarTypeHandler. As a result, it is not necessary to overrideshapeandcontained_type. Then, in theextractmethod, we extract the value and return it as a NumPy data type.The implemntation of a custom type handler relies heavily on the GDB Python API, particularlygdb.Valueandgdb.Type. Documentation for the API can be found at the followinglink.AcknowledgementsSpecial thanks toBrian Hone, whosegdb-plotserved as the inspiration for this project.