# GDBplotlib
GDBplotlib 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. [Ken Mankoff](https://github.com/mankoff) has created a fork that adds Fortan support, which can be found [here](https://github.com/mankoff/gdbplotlib/tree/fortran).
## Features
* Many different visualisations, such as line graphs, scatter plots and histograms
* Exporting of variables in `.mat`, Python pickle and binary formats
* Works for arbitrarily nested data structures
* Slice support
* Can be easily extended to work with any custom type
## Requirements
* GDB >= 7.0
* Python 3
* NumPy
* Matplotlib
* Scipy (OPTIONAL - for exporting to `.mat`)
## Installation
GDBplotlib can be installed via `pip`:
```bash
$ pip install gdbplotlib
```
To make GDBplotlib available in GDB sessions, add the following lines to `~/.gdbinit` (or create it if it doesn't exist):
```bash
python
import gdbplotlib
end
```
## Usage Examples
Consider the following C++ program:
```cpp
#include <vector>
#include <array>
int main()
{
std::array<double, 6> x = {0.1, 0.9, 0.8, 0.7, 0.2, 0.1};
int* y = new int[100];
for (int i = 0; i < 100; ++i) {
y[i] = 50 - i + int(5e-3 * i * i);
}
std::vector<std::array<int*, 10>> z(10);
for (int i = 0; i < z.size(); ++i) {
for (int j = 0; j < z[i].size(); ++j) {
z[i][j] = new int[10];
for (int k = 0; k < 10; ++k) {
z[i][j][k] = i + 2*j + 3*k;
}
}
}
return 0;
}
```
To create a line graph of `x`, execute the command:
```
plot x
```
![Image](./images/example_1.png)
GDBplotlib has full support for Python-style slicing. For example, to plot only the first 3 elements, simply execute:
```
plot x[:3]
```
![Image](./images/example_2.png)
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 variable `y`, the user must explicitily give an endpoint using the slice syntax:
```
plot y[:100]
```
![Image](./images/example_3.png)
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 of `z`, run:
```
plot3d z[::-1,2,4:8]
```
![Image](./images/example_4.png)
## Supported Types
* `std::vector`
* `std::array`
* C-style array
* Pointer
* All integral and floating point types
* `std::complex<float>` and `std::complex<double>`
## Supported Commands
* `plot VAR...` - Create a 1D line plot of `VAR`, where `VAR` is any 1D or 2D structure
* `plot3d VAR` - Create a 2D surface plot of `VAR`, where `VAR` is a 2D real-valued structure
* `scatter VAR...` - Create a 2D scatter plot of `VAR`, where `VAR` is either a 1D complex-valued structure, an N-by-2 real-valued structure, or two 1D real-valued structures
* `scatter3d VAR...` - Create a 3D scatter plot of `VAR`, where `VAR` is either an N-by-3 real-valued structure, or three 1D real-valued structures
* `hist VAR...` - Create a histogram plot of `VAR`, where `VAR` is any 1D or 2D structure
* `fft VAR...` - Create a power spectral density plot of `VAR`, where `VAR` is any 1D structure
* `save FILE VAR` - Save `VAR` to the file `FILE` in binary format
* `savepy FILE VAR` - Save `VAR` to the file `FILE` in Python pickle format
* `savemat FILE VAR...` - Save `VAR` to the file `FILE` in Matlab format
## Custom Types
It is easy to extend GDBplotlib to handle any desired type. Let's look at an example of how we might implement support for `std::vector`:
```python
from gdbplotlib.type_handler import TypeHandler
from gdbplotlib.default import default
class StdVector(TypeHandler):
@staticmethod
def can_handle(gdb_type: gdb.Type) -> bool:
return str(gdb_type).startswith("std::vector")
def shape(self, gdb_value: gdb.Value) -> Tuple[Optional[int], ...]:
size = int(gdb_value["_M_impl"]["_M_finish"] - gdb_value["_M_impl"]["_M_start"])
return (size,)
def contained_type(self, gdb_value: gdb.Value) -> gdb.Type:
return gdb_value.type.template_argument(0)
def extract(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 class `gdbplotlib.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 a `std::vector`, we want to handle any type whose name begins with `std::vector`
* `shape` - 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 of `None`. A `std::vector` is 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 a `std::vector`, it is the first template argument.
* `extract` - Given an index, extract an element from the container. The `index` parameter is an `n`-length tuple, where `n` is the number of dimensions of the container. For a `std::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.
```python
class Float(ScalarTypeHandler):
@staticmethod
def can_handle(gdb_type: gdb.Type) -> bool:
return str(gdb_type) == "float"
def extract(self, gdb_value: gdb.Value, index: Tuple[int, ...]):
return np.float32(gdb_value)
```
Handling a custom scalar type is a similar process. The main difference is that we derive from `gdbplotlib.ScalarTypeHandler`. As a result, it is not necessary to override `shape` and `contained_type`. Then, in the `extract` method, 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, particularly `gdb.Value` and `gdb.Type`. Documentation for the API can be found at the following [link](https://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html).
## Acknowledgements
Special thanks to [Brian Hone](https://github.com/bthcode), whose [gdb-plot](https://github.com/bthcode/gdb-plot) served as the inspiration for this project.
Raw data
{
"_id": null,
"home_page": "https://github.com/X-Neon/gdbplotlib",
"name": "gdbplotlib",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3",
"maintainer_email": null,
"keywords": "gdb, debug",
"author": "George Cholerton",
"author_email": "gcholerton@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/f5/37/51373758dabdacbcac556e7e8db6d41bb623b6efca4501718cb80666636d/gdbplotlib-0.3.0.tar.gz",
"platform": null,
"description": "# GDBplotlib\n\nGDBplotlib 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. [Ken Mankoff](https://github.com/mankoff) has created a fork that adds Fortan support, which can be found [here](https://github.com/mankoff/gdbplotlib/tree/fortran).\n\n## Features\n\n* Many different visualisations, such as line graphs, scatter plots and histograms\n* Exporting of variables in `.mat`, Python pickle and binary formats\n* Works for arbitrarily nested data structures\n* Slice support\n* Can be easily extended to work with any custom type\n\n## Requirements\n\n* GDB >= 7.0\n* Python 3\n* NumPy\n* Matplotlib\n* Scipy (OPTIONAL - for exporting to `.mat`)\n\n## Installation\n\nGDBplotlib can be installed via `pip`:\n\n```bash\n$ pip install gdbplotlib\n```\n\nTo make GDBplotlib available in GDB sessions, add the following lines to `~/.gdbinit` (or create it if it doesn't exist):\n\n```bash\npython\nimport gdbplotlib\nend\n```\n\n## Usage Examples\n\nConsider the following C++ program:\n\n```cpp\n#include <vector>\n#include <array>\n\nint main()\n{\n std::array<double, 6> x = {0.1, 0.9, 0.8, 0.7, 0.2, 0.1};\n\n int* y = new int[100];\n for (int i = 0; i < 100; ++i) {\n y[i] = 50 - i + int(5e-3 * i * i);\n }\n\n std::vector<std::array<int*, 10>> z(10);\n for (int i = 0; i < z.size(); ++i) {\n for (int j = 0; j < z[i].size(); ++j) {\n z[i][j] = new int[10];\n for (int k = 0; k < 10; ++k) {\n z[i][j][k] = i + 2*j + 3*k;\n }\n }\n }\n\n return 0;\n}\n```\n\nTo create a line graph of `x`, execute the command:\n\n```\nplot x\n```\n![Image](./images/example_1.png)\n\nGDBplotlib has full support for Python-style slicing. For example, to plot only the first 3 elements, simply execute:\n\n```\nplot x[:3]\n```\n![Image](./images/example_2.png)\n\nPointers 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 variable `y`, the user must explicitily give an endpoint using the slice syntax:\n\n```\nplot y[:100]\n```\n![Image](./images/example_3.png)\n\nNote 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).\n\nGDBplotlib supports data extraction of arbitrarily nested structures. For example, to create a 3D plot of `z`, run:\n\n```\nplot3d z[::-1,2,4:8]\n```\n![Image](./images/example_4.png)\n\n## Supported Types\n\n* `std::vector`\n* `std::array`\n* C-style array\n* Pointer\n* All integral and floating point types\n* `std::complex<float>` and `std::complex<double>`\n\n## Supported Commands\n\n* `plot VAR...` - Create a 1D line plot of `VAR`, where `VAR` is any 1D or 2D structure\n* `plot3d VAR` - Create a 2D surface plot of `VAR`, where `VAR` is a 2D real-valued structure\n* `scatter VAR...` - Create a 2D scatter plot of `VAR`, where `VAR` is either a 1D complex-valued structure, an N-by-2 real-valued structure, or two 1D real-valued structures\n* `scatter3d VAR...` - Create a 3D scatter plot of `VAR`, where `VAR` is either an N-by-3 real-valued structure, or three 1D real-valued structures\n* `hist VAR...` - Create a histogram plot of `VAR`, where `VAR` is any 1D or 2D structure\n* `fft VAR...` - Create a power spectral density plot of `VAR`, where `VAR` is any 1D structure\n* `save FILE VAR` - Save `VAR` to the file `FILE` in binary format\n* `savepy FILE VAR` - Save `VAR` to the file `FILE` in Python pickle format\n* `savemat FILE VAR...` - Save `VAR` to the file `FILE` in Matlab format\n\n## Custom Types\n\nIt is easy to extend GDBplotlib to handle any desired type. Let's look at an example of how we might implement support for `std::vector`:\n\n```python\nfrom gdbplotlib.type_handler import TypeHandler\nfrom gdbplotlib.default import default\n\n\nclass StdVector(TypeHandler):\n @staticmethod\n def can_handle(gdb_type: gdb.Type) -> bool:\n return str(gdb_type).startswith(\"std::vector\")\n\n def shape(self, gdb_value: gdb.Value) -> Tuple[Optional[int], ...]:\n size = int(gdb_value[\"_M_impl\"][\"_M_finish\"] - gdb_value[\"_M_impl\"][\"_M_start\"])\n return (size,)\n\n def contained_type(self, gdb_value: gdb.Value) -> gdb.Type:\n return gdb_value.type.template_argument(0)\n\n def extract(self, gdb_value: gdb.Value, index: Tuple[int, ...]):\n return (gdb_value[\"_M_impl\"][\"_M_start\"] + index[0]).dereference()\n\n\ndefault.register(StdVector)\n```\n\nTo handle a custom type, we must create a class derived from the abstract base class `gdbplotlib.TypeHandler`. There are 4 methods that need to be overriden:\n\n* `can_handle` - Given a type, determine whether this handler is able to handle it. For a `std::vector`, we want to handle any type whose name begins with `std::vector`\n* `shape` - 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 of `None`. A `std::vector` is 1-dimensional, with a size equal to the difference between the start and end pointers.\n* `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 a `std::vector`, it is the first template argument.\n* `extract` - Given an index, extract an element from the container. The `index` parameter is an `n`-length tuple, where `n` is the number of dimensions of the container. For a `std::vector`, we increment the start pointer by the first (and only) index, and dereference to get the value.\n\nFinally, 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.\n\n```python\nclass Float(ScalarTypeHandler):\n @staticmethod\n def can_handle(gdb_type: gdb.Type) -> bool:\n return str(gdb_type) == \"float\"\n\n def extract(self, gdb_value: gdb.Value, index: Tuple[int, ...]):\n return np.float32(gdb_value)\n```\n\nHandling a custom scalar type is a similar process. The main difference is that we derive from `gdbplotlib.ScalarTypeHandler`. As a result, it is not necessary to override `shape` and `contained_type`. Then, in the `extract` method, we extract the value and return it as a NumPy data type.\n\nThe implemntation of a custom type handler relies heavily on the GDB Python API, particularly `gdb.Value` and `gdb.Type`. Documentation for the API can be found at the following [link](https://sourceware.org/gdb/current/onlinedocs/gdb/Python-API.html).\n\n## Acknowledgements\n\nSpecial thanks to [Brian Hone](https://github.com/bthcode), whose [gdb-plot](https://github.com/bthcode/gdb-plot) served as the inspiration for this project.\n",
"bugtrack_url": null,
"license": null,
"summary": "Plotting and exporting of variables from GDB",
"version": "0.3.0",
"project_urls": {
"Homepage": "https://github.com/X-Neon/gdbplotlib"
},
"split_keywords": [
"gdb",
" debug"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "50d638c94a1be1b570b4094e86a6892269207c98475718ee145a9b8cdaafda36",
"md5": "a5e09ea4839b54ba8182ee9c87b1e5a2",
"sha256": "c4319e0622bdd5a2d0de1e3c436f1acb3ad70f0c86a81bb0c0a7ad1db1911d4c"
},
"downloads": -1,
"filename": "gdbplotlib-0.3.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a5e09ea4839b54ba8182ee9c87b1e5a2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3",
"size": 11441,
"upload_time": "2024-09-16T21:31:09",
"upload_time_iso_8601": "2024-09-16T21:31:09.526817Z",
"url": "https://files.pythonhosted.org/packages/50/d6/38c94a1be1b570b4094e86a6892269207c98475718ee145a9b8cdaafda36/gdbplotlib-0.3.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f53751373758dabdacbcac556e7e8db6d41bb623b6efca4501718cb80666636d",
"md5": "dfbba1eefc2378b3eac51f5243d2575b",
"sha256": "781002d857d9260b338987a35d95ede82dcd6281f43b8c4e4547a28bb84ea271"
},
"downloads": -1,
"filename": "gdbplotlib-0.3.0.tar.gz",
"has_sig": false,
"md5_digest": "dfbba1eefc2378b3eac51f5243d2575b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3",
"size": 11807,
"upload_time": "2024-09-16T21:31:10",
"upload_time_iso_8601": "2024-09-16T21:31:10.575421Z",
"url": "https://files.pythonhosted.org/packages/f5/37/51373758dabdacbcac556e7e8db6d41bb623b6efca4501718cb80666636d/gdbplotlib-0.3.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-16 21:31:10",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "X-Neon",
"github_project": "gdbplotlib",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "gdbplotlib"
}