Full Code of cs01/gdbgui for AI

master 773b9161729e cached
143 files
526.7 KB
141.3k tokens
463 symbols
1 requests
Download .txt
Showing preview only (562K chars total). Download the full file or copy to clipboard to get everything.
Repository: cs01/gdbgui
Branch: master
Commit: 773b9161729e
Files: 143
Total size: 526.7 KB

Directory structure:
gitextract_zcfu_6aw/

├── .eslintrc.json
├── .flake8
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── build_executable.yml
│       └── tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode/
│   └── settings.json
├── .vulture_whitelist.py
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── docs/
│   ├── CNAME
│   ├── api.md
│   ├── contact.md
│   ├── examples.md
│   ├── faq.md
│   ├── gettingstarted.md
│   ├── guides.md
│   ├── howitworks.md
│   ├── index.md
│   ├── installation.md
│   └── screenshots.md
├── examples/
│   ├── .gitignore
│   ├── README.md
│   ├── c/
│   │   ├── debug_segfault.c
│   │   ├── hello.c
│   │   ├── input.c
│   │   ├── makefile
│   │   ├── sleeper.c
│   │   ├── threads.c
│   │   └── tree.c
│   ├── cpp/
│   │   ├── hello.cpp
│   │   ├── linked_list.cpp
│   │   ├── makefile
│   │   ├── sin.cpp
│   │   └── smart_ptr_demo.cpp
│   ├── fortran/
│   │   ├── fortran_array.f90
│   │   └── makefile
│   ├── golang/
│   │   ├── hello.go
│   │   └── makefile
│   └── rust/
│       ├── .gitignore
│       ├── Cargo.toml
│       ├── README.md
│       ├── compile_and_debug.sh
│       └── src/
│           └── main.rs
├── gdbgui/
│   ├── SSLify.py
│   ├── VERSION.txt
│   ├── __init__.py
│   ├── __main__.py
│   ├── cli.py
│   ├── htmllistformatter.py
│   ├── py.typed
│   ├── server/
│   │   ├── __init__.py
│   │   ├── app.py
│   │   ├── constants.py
│   │   ├── http_routes.py
│   │   ├── http_util.py
│   │   ├── ptylib.py
│   │   ├── server.py
│   │   └── sessionmanager.py
│   ├── src/
│   │   └── js/
│   │       ├── Actions.ts
│   │       ├── BinaryLoader.tsx
│   │       ├── Breakpoints.tsx
│   │       ├── ControlButtons.tsx
│   │       ├── CopyToClipboard.tsx
│   │       ├── Expressions.tsx
│   │       ├── FileOps.tsx
│   │       ├── FileSystem.tsx
│   │       ├── FoldersView.tsx
│   │       ├── GdbApi.tsx
│   │       ├── GdbMiOutput.tsx
│   │       ├── GdbVariable.tsx
│   │       ├── GdbguiModal.tsx
│   │       ├── GlobalEvents.ts
│   │       ├── HoverVar.tsx
│   │       ├── InferiorProgramInfo.tsx
│   │       ├── InitialStoreData.ts
│   │       ├── Links.tsx
│   │       ├── Locals.tsx
│   │       ├── Memory.tsx
│   │       ├── MemoryLink.tsx
│   │       ├── MiddleLeft.tsx
│   │       ├── ReactTable.tsx
│   │       ├── Registers.tsx
│   │       ├── RightSidebar.tsx
│   │       ├── Settings.tsx
│   │       ├── SourceCode.tsx
│   │       ├── SourceCodeHeading.tsx
│   │       ├── SourceFileAutocomplete.tsx
│   │       ├── StatusBar.tsx
│   │       ├── Terminals.tsx
│   │       ├── Threads.tsx
│   │       ├── ToolTip.tsx
│   │       ├── ToolTipTourguide.tsx
│   │       ├── TopBar.tsx
│   │       ├── Tree.ts
│   │       ├── Util.ts
│   │       ├── constants.ts
│   │       ├── dashboard.tsx
│   │       ├── gdbgui.tsx
│   │       ├── processFeatures.ts
│   │       ├── process_gdb_response.tsx
│   │       ├── register_descriptions.ts
│   │       ├── tests/
│   │       │   └── Util.jest.ts
│   │       └── types.d.ts
│   ├── static/
│   │   ├── css/
│   │   │   ├── gdbgui.css
│   │   │   ├── splitjs-gdbgui.css
│   │   │   └── tailwind.css
│   │   └── vendor/
│   │       ├── css/
│   │       │   ├── animate.css
│   │       │   ├── gdbgui_awesomeplete.css
│   │       │   └── pygments/
│   │       │       ├── emacs.css
│   │       │       ├── light.css
│   │       │       ├── monokai.css
│   │       │       └── vim.css
│   │       └── js/
│   │           └── splitjs.min-1.2.0.js
│   └── templates/
│       ├── dashboard.html
│       └── gdbgui.html
├── images/
│   ├── gdbgui.xcf
│   ├── gdbgui_small.xcf
│   └── gdbgui_square.xcf
├── jest.config.js
├── make_executable.py
├── mkdocs.yml
├── noxfile.py
├── package.json
├── postcss.config.js
├── requirements.in
├── requirements.txt
├── setup.py
├── tailwind.config.js
├── tests/
│   ├── __init__.py
│   ├── test_backend.py
│   ├── test_cli.py
│   ├── test_ptylib.py
│   └── test_sessionmanager.py
├── tsconfig.json
├── tslint.json
└── webpack.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.json
================================================
{
  "env": {
    "browser": true,
    "es6": true,
    "jquery": true
  },
  "globals": {
    "initial_data": true,
    "module": true,
    "_": true,
    "moment": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaFeatures": {
      "experimentalObjectRestSpread": true,
      "jsx": true
    },
    "sourceType": "module"
  },
  "plugins": ["react"],
  "rules": {
    "no-console": [0],
    "react/jsx-uses-vars": 1
  },
  "parser": "babel-eslint"
}


================================================
FILE: .flake8
================================================
[flake8]
max-line-length = 88
ignore = E501, E203, W503, E402, E231
# line length, whitespace before ':', line break before binary operator,  module level import not at top of file


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Please complete the following information:**
* OS: 
* gdbgui version (`gdbgui -v`):
* gdb version (`gdb -v`):
* browser [e.g. chrome, safari]:
* python packages (`pip freeze`):


**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!-- add an 'x' in the brackets below -->
- [] I have added an entry to `CHANGELOG.md`, or an entry is not needed for this change

## Summary of changes
<!-- 
* fixed bug
* added new feature 
-->

## Test plan
<!-- provide evidence of testing, preferably with command(s) that can be copy+pasted by others -->
Tested by running
```
# command(s) to exercise these changes
```


================================================
FILE: .github/workflows/build_executable.yml
================================================
name: Build native gdbgui executables with pyinstaller and pex

on:
  pull_request:
  push:
    branches:
      - master
  release:

jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
        python-version: ["3.13"]
        include:
          - os: ubuntu-latest
            buildname: linux
          # - os: windows-latest
          #   buildname: windows
          - os: macos-latest
            buildname: mac
    steps:
      - uses: actions/checkout@v1
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v2
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install nox
      - name: Compile ${{ matrix.buildname }} gdbgui executable
        run: |
          nox --non-interactive --session build_executables_${{ matrix.buildname }}
      - name: Upload ${{ matrix.buildname }} executable
        uses: actions/upload-artifact@v4
        with:
          name: gdbgui_${{ matrix.buildname }}
          path: ./build/executable
          if-no-files-found: error  # Optional: warn, error, or ignore
          retention-days: 90      # Optional: 1-90 days, or repo default            



================================================
FILE: .github/workflows/tests.yml
================================================
# https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions

name: Tests

on:
  pull_request:
  push:
    branches:
      - master
  release:

jobs:
  run_tests:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        python-version: ["3.13"]

    steps:
      - uses: actions/checkout@v2
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v2
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install nox
      - name: Install gdb ubuntu
        run: |
          sudo apt update
          sudo apt upgrade
          sudo apt install gdb
      - name: Execute Tests
        run: |
          nox --non-interactive --session tests-${{ matrix.python-version }}

  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        python-version: ["3.13"]

    steps:
      - uses: actions/checkout@v2
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v2
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install nox
      - name: Execute Tests
        run: |
          nox --non-interactive --session build

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: 3.13
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install nox
      - name: Lint
        run: |
          nox --non-interactive --session lint

  docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: "3.13"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install nox
      - name: Verify Docs
        run: |
          nox --non-interactive --session docs


================================================
FILE: .gitignore
================================================
dist
*egg*
node_modules
build
executable
.DS_Store
*.a.dSYM
gdbgui_pyinstaller.spec
*-link
*-link.c
*-link.dSYM
*.pyc
yarn-error.log
venv
site
gdbgui/static/js/*
__pycache__
.coverage*


================================================
FILE: .prettierrc.js
================================================
module.exports = {
  printWidth: 90,
}


================================================
FILE: .vscode/settings.json
================================================
{
    "python.formatting.provider": "none",
    "[python]": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "ms-python.black-formatter"
    },
    "[json]": {
        "editor.formatOnSave": true
    },
    "files.associations": {
        "*.spec": "python"
    }
}

================================================
FILE: .vulture_whitelist.py
================================================
_.sessions  # unused attribute (noxfile.py:7)
_.reuse_existing_virtualenvs  # unused attribute (noxfile.py:6)
_.secret_key  # unused attribute (gdbgui/backend.py:104)
_.reuse_existing_virtualenvs  # unused attribute (noxfile.py:6)
_.sessions  # unused attribute (noxfile.py:7)
cover  # unused function (noxfile.py:50)
lint  # unused function (noxfile.py:78)
autoformat  # unused function (noxfile.py:94)
docs  # unused function (noxfile.py:103)
develop  # unused function (noxfile.py:109)
serve  # unused function (noxfile.py:118)
publish  # unused function (noxfile.py:133)
watch_docs  # unused function (noxfile.py:142)
build_executable_current_platform  # unused function (noxfile.py:154)
build_executable_mac  # unused function (noxfile.py:162)
build_executable_linux  # unused function (noxfile.py:169)
build_executable_windows  # unused function (noxfile.py:176)
on_connect  # unused function (tests/test_backend.py:14)
monkeypatch  # unused variable (tests/test_cli.py:23)
monkeypatch  # unused variable (tests/test_cli.py:33)
monkeypatch  # unused variable (tests/test_cli.py:43)


================================================
FILE: CHANGELOG.md
================================================
# gdbgui release history

## 0.15.3.0
- Update default python version to 3.13

## 0.15.2.0
- Update default python version to 3.12
- utf-8 decode error bugfix
- fix registers cannot be displayed bug

## 0.15.1.0

- Compatibility with Werkzeug 2.1. Use the eventlet server instead of
  the Werkzeug development server.
- Use pinned requirements instead of abstract requirements to ensure reproducability of pip installs

## 0.15.0.1

This release has no changes to features or usability. The only change is to include a file used by other package maintainers.

- Include all files needed to rebuild from source (#403)

## 0.15.0.0

This release is focused mostly on Python 3.9 compatibility and updating dependencies

- Support only Python 3.9 (though other Python versions may still work)
- Build gdbgui as a [pex](https://pypi.org/project/pex/) executable.
  - These are executable Python environments that are self-contained with the exception of requiring a specific Python version installed in the environment running the executable. The pex executables should have better compatibility than PyInstaller executables, which sometimes have missing shared libraries depending on the operating system.
- Use only the threading async model for flask-socketio. No longer support gevent or eventlet.
- [bugfix] Catch exception if gdb used in tty window crashes instead of gdbgui crashing along with it
- Disable pagination in gdb tty by default. It can be turned back on with `set pagination off`.
- Upgrade various dependencies for both the backend and frontend (Python and JavaScript)
- Display gdbgui version in "about" and "session information"

## 0.14.0.2

- Pinned python-socketio version
- Pinned mypy version to unbreak linting
- Fixed reverse debugging commands that were broken when `--gdb` flag was removed

## 0.14.0.1

- Fix import paths
- Pin broken dependency to avoid segfault
- Hide "No registers." message

## 0.14.0.0

**Breaking Changes**

- Removed support for Windows
- Replaced `--gdb` flag with `--gdb-cmd`. The `--gdb-cmd` argument specifies the gdb executable as well as all arguments you wish to pass to gdb at startup, for example `--gdb-cmd "gdb -nx"`. The existing `-g` argument is an alias for `--gdb-cmd`.
- Removed `--rr` flag. Use `--gdb-cmd "rr replay --"` instead.
- Removed deprecated and hidden `--hide-gdbgui-upgrades` argument. It will now raise an error.

**Additional Changes**

- Replaced single terminal on frontend with three terminals: an interactive xterm terminal running gdb, a gdbgui console for diagnostic messages, and a terminal connected to the inferior application being debugged.
- Updates to the dashboard
- Add ability to specify gdb command from the browser. This can now be accomplished from the dashboard.
- Removed gdbgui binaries from source control. They can now be downloaded as artifacts of [releases](https://github.com/cs01/gdbgui/releases).
- [documentation] Fix bug when generating md5 checksum for binary releases
- Remove "shutdown" button in UI

## 0.13.2.1

- No end user changes. This release builds the gdbgui executables with GitHub actions.

## 0.13.2.0

- Print number of times a breakpoint was hit (@MatthiasKreileder).
- Publish sdist to PyPI (this was overlooked in previous release).
- Do not notify users of gdbgui upgrades (deprecate `--hide-gdbgui-upgrades` flag)
- Drop support for Python 3.4
- [dev] Some infrastructure changes to gdbgui. End users should not be affected.
- [dev] Fix build error due to webpack bug (https://github.com/webpack/webpack/issues/8082).

## 0.13.1.2

- Exclude "tests" directory from Python package
- Remove analytics from documentation

## 0.13.1.1

- Add `__main__` entrypoint

## 0.13.1.0

- Remove automatic flushing of stdout and require newer version of pygdbmi
- Add flake8 tests to CI build

## 0.13.0.0

- Add ability to re-map source file paths. Added flags `--remap-sources` and `-m` to replace compile-time source paths to local source paths. i.e. `gdbgui --remap-sources='{"/buildmachine": "/home/chad"}'` (#158)
- Add shift keyboard shortcut to go in reverse when using rr (#201)
- Pass arbitrary gdb arguments directly to gdb: added `--gdb-args` flag
- Removed `-x` CLI option, which caused major version to change. New way to pass is `gdbgui --gdb-args='-x=FILE'` (#205)
- Add "name" to Threads (new gdb 8.1 feature) (@P4Cu)
- Fix crash/black screen from "Python Exception <class NameError> name long is not defined" #212
- Fix bug when debugging filenames with spaces (Fix Cannot create breakpoint: -break-insert: Garbage following <location> #211")
- Fix empty frame causes the ui to crash/black screen #216
- Update npm packages; update react to 16.4
- Update prettier rules
- Update tour text + fix typo in tour (@nkirkby)

## 0.12.0.0

- Add pause button
- Update command line parsing for cmd and --args, change arguments from underscore to hyphen, add option to specify browser (@fritzr)
- Add tour
- Run `set breakpoint pending on` on initial connection
- Allow signal to be sent to arbitrary PIDs
- Fix bug when sending signals in Python2
- Move signal component lower in side pane
- Update Rust documentation
- Make requirements.txt point to setup.py's dependencies

## 0.11.3.1

- Limit maximum Flask version to prevent `Session expired. Please refresh this webpage.` error
- Rename "premium" to "ad-free"
- Do smarter version checking
- Fix bug when trying to view "about"

## 0.11.3.0

- ensure expressions with hex values are parsed and updated appropriately (#182)
- improve command line arguments
- use python logging module

## 0.11.2.1

- Small bugfix for specific platforms when reading version number

## 0.11.2.0

- add option to remove fflush command (#179)
- remove react-treebeard and render filesystem w/ new component

## 0.11.1.1

- Bugfix displaying upgrade text

## 0.11.1.0

- Add csrf and cross origin protection
- Convert backslashes to forward slashes when entering windows binary paths (#167)
- Fix safari ui issue (#164)
- Update text on reload file button, and disable when no file is loaded (#165)
- When disassembly can't be fetched in mode 4, fetch in mode 3 and assume gdb version is 7.6.0 (#166)
- Add copy to clipboard icon for files and variables
- Allow SSL module import to fail and print warning (#170)
- Cleanup menu, add license info, bugfixes, etc. (#169, #136, #163, #172)

## 0.11.0.0

- Replace `--auth` cli option with `--user` and `--password`

## 0.10.3.0

- Added resizer buttons to components on right pane

## 0.10.2.1

- Add link for fix for macOS users
- Update version of React to 16.2
- Remove unused links

## 0.10.2.0

- Add folders view, rearrange layout (@martin-der)
- Add settings cog button
- Add message when sending signal to inferior process (#156)
- Change default theme to monokai, rename 'default' theme to 'light'
- Minor bugfixes

## 0.10.1.0

- Display descriptions of registers
- Do not try to fetch Registers when they cannot be read

## 0.10.0.2

- Add support for rr (--rr flag)
- Add dashboard to connect to/kill existing gdb processes
- Add option to specify SSL key and certificate to enable https
- Add option to connect to process
- Add option to connect to gdbserver
- Add infinite scrolling

## 0.9.4.1

- Remove `pypugjs` dependency

## 0.9.4.0

- Add native Windows support (no longer relies on Cygwin)

## 0.9.3.0

- Only display assembly flavor is assembly is displayed
- Add new output type to console (gdbgui output)
- Add dashboard link and dropdown for gdb server/pid attach
- Handle invalid signal choice better
- Print gdb mi log messages to console
- Remove localStorage keys when they are invalid

## 0.9.2.0

- Add signals component and allow signals to be sent to gdb (issue ##141)
- Fix bug when jumping to line of source file

## 0.9.1.1

- Fix bug when passing arguments to gdb
- Require latest version of pygdbmi for faster parsing of large gdb output

## 0.9.1.0

- Lazily load files (issue #131)
- Update setup.py to build wheels

## 0.9.0.1

- Reupload to fix setup.cfg PyPI bug

## 0.9.0.0

- Compress responses from server (massive bandwidth improvement)
- Add button to toggle assembly flavors (issue #110)
- Parse executable+args with spaces (issue #116)
- Turn modals into components
- Move everything into a single root React component
- Refresh state when clicking "return" button
- Add javascript unit tests

## 0.8.2.0

- Add optional authentication (@nickamon, issue #132)
- Support the `--args` flag (issue #126)
- Ensure code is correct and adheres to recommended Python style when running tests/building (flake8)
- Display source when running `backtrace` (fix regression, #134)

## 0.8.1.0

- Add autocomplete functionality (@bobthekingofegypt, issue #129)
- Rearranged and improved alignment of assembly
- Fixed bug when fetching variable fails
- Plot floating point values instead of casting to int

## 0.8.0.3

- modify component initialization order so that store updates are better sequenced

## 0.8.0.2

- display bracket instead of `&lt;` when exploring gdb variables

## 0.8.0.1

- fix bug when restoring old settings

## 0.8.0.0

- Add ability to change radix of variables (issue #102)
- Add component to send signals to inferior program (issues #31, #90)
- Parse gdb version from arm-non-eabi-gdb (issue #83)
- Rewrite most components to React (issue #17)
- Improve CSS in various components

## 0.7.9.5

- re-fetch registers if name/value count does not match

## 0.7.9.4

- add inputs to resize Tree view
- add menu in top right
- css updates to preserve whitespace in terminal
- add top-level html to wrap body+head elements in gdbgui.pug
- add help file
- add donate page

## 0.7.9.3

- Changes to layout
- Fix character escaping in breakpoint line display

## 0.7.9.2

- Fix firefox css bug
- Update examples
- Update readme for windows (cygwin) users (thanks tgharib)

## 0.7.9.1

- Collapse simple fields to the parent node in tree explorer
- Add button to re-enter program state when signals are received (i.e. SEGFAULT)

## 0.7.9.0

- Add interactive tree explorer of variables

## 0.7.8.3

- Remove optimization for fetching registers due to potential bug

## 0.7.8.2

- bugfix in logic when jumping to source code line
- bugfix for when variable goes from`empty -> 1 element`
- add CODE OF CONDUCT, CONTRIBUTING, and CHANGELOG files

## 0.7.8.1

- correctly display `<` and `>` in console widget

## 0.7.8.0

- show disassembly when file is unknown or missing
- show new children in expressions widget when they are dynamically added by application (@wuyihao)
- suppress nuisance errors when hover variable or fflush command is not found
- improve logic when source code line should be jumped to
- escape brackets in disassembly, and gracefully hide missing opcodes
- update socketio version for more reliable websocket connection

## 0.7.7.0

- Show variable values when hovering in source code
- gracefully handle hostname not being present in /etc/hosts when running with remote flag
- Use external state management library (`stator.js`) for client ui


================================================
FILE: CONTRIBUTING.md
================================================
Thanks for your interest in contributing to gdbgui!

If your change is small, go ahead and submit a pull request. If it is substantial, create a GitHub issue to discuss it before making the change.

## Dependencies

1.) [nox](https://github.com/theacodes/nox) is used to automate various tasks. You will need it installed on your system before continuing.

You can install it with pipx (recommended):
```
> pipx install nox
```
or pip:
```
> pip install --user nox
```

2.) [yarn](https://yarnpkg.com/) is used for managing JavaScript files

## Developing
Development can be done with one simple step:
```
> nox -s develop
```
This will install all Python and JavaScript dependencies, and build and watch Python and JavaScript files for changes, automatically reloading as things are changed.

Make sure you [turn your cache off](https://www.technipages.com/google-chrome-how-to-completely-disable-cache) so that changes made locally are reflected in the page.

## Running and Adding tests
```bash
> nox
```

runs all applicable tests and linting.

Python tests are in `gdbgui/tests`. They are run as part of the above command, but can be run with
```
> nox -s python_tests
```

JavaScript tests are in `gdbgui/src/js/tests`. They are run as part of the above command, but can be run with
```
> nox -s js_tests
```

## Documentation

### Modifying Documentation
Documentation is made with `mkdocs`. Then make changes to `mkdocs.yml` or md files in the `docs` directory.

To build docs, run
```
nox -s docs
```

To see a live preview of current documentation, run
```
nox -s watch_docs
```

### Publishing Documentation
The generated documentation is published to the `gh-pages` branch.
```
nox -s publish_docs
```

### Building Binary Executables

These are automatically built on CI, but can be built locally with corresponding `nox` commands, such as:

```
nox -s build_executables_current_platform
```

## Publishing a New Version
1. Make sure the version number is incremented in `VERSION.txt`.
1. The version to release must be on the master branch and have all CI tests pass and new binary executable artifacts attached to the GitHub action results
1. Publish the package to PyPI and update documentation. Both are done with this `nox -s publish`.
1. Create a "release" in GitHub and attach the gdbgui binary executable artifacts to it.



================================================
FILE: LICENSE
================================================
Copyright (C) Chad Smith (Grass Fed Code)

                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    {one line to give the program's name and a brief idea of what it does.}
    Copyright (C) {year}  {name of author}

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    {project}  Copyright (C) {year}  {fullname}
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.


================================================
FILE: MANIFEST.in
================================================
include README.md
include LICENSE
include requirements.txt

graft gdbgui
# these files are built and must be included in distribution
# but shouldn't be included in git repository since they
# are generated
graft gdbgui/static/js

prune examples
prune .vscode
prune downloads
prune screenshots
prune tests
prune docs
prune docker
prune images
prune gdbgui/__pycache__
prune gdbgui/server/__pycache__
prune gdbgui/src

exclude mypy.ini
exclude .eslintrc.json
exclude .coveragerc
exclude .flake8
exclude .vulture_whitelist.py
exclude .prettierrc.js
exclude jest.config.js
exclude make_executable.py
exclude mkdocs.yml
exclude package.json
exclude requirements.in
exclude tsconfig.json
exclude tslint.json
exclude webpack.config.js
exclude yarn.lock
exclude noxfile.py
exclude CHANGELOG.md
exclude CONTRIBUTING.md
exclude postcss.config.js
exclude tailwind.config.js


================================================
FILE: README.md
================================================
<p align="center">
<a href="http://gdbgui.com"><img src="https://github.com/cs01/gdbgui/raw/master/images/gdbgui_banner.png"></a>
</p>

<h3 align="center">
A browser-based frontend to gdb (gnu debugger)
</h3>

<p align="center">

<a href="https://github.com/cs01/gdbgui/actions">
<img src="https://github.com/cs01/gdbgui/workflows/Tests/badge.svg?branch=master" alt="image" /></a>

<a href="https://badge.fury.io/py/gdbgui">
<img src="https://badge.fury.io/py/gdbgui.svg" alt="PyPI version" >
</a>

<img src="https://pepy.tech/badge/gdbgui" alt="image" />

</p>

---

**Documentation**: https://gdbgui.com

**Source Code**: https://github.com/cs01/gdbgui/


================================================
FILE: docs/CNAME
================================================
www.gdbgui.com

================================================
FILE: docs/api.md
================================================
This is the command line help output of gdbgui.

```
usage: gdbgui [-h] [-g GDB_CMD] [-p PORT] [--host HOST] [-r]
              [--auth-file AUTH_FILE] [--user USER] [--password PASSWORD]
              [--key KEY] [--cert CERT] [--remap-sources REMAP_SOURCES]
              [--project PROJECT] [-v] [-n] [-b BROWSER] [--debug]
              [--args ...]
              [debug_program]

A server that provides a graphical user interface to the gnu debugger (gdb).
https://github.com/cs01/gdbgui

positional arguments:
  debug_program         The executable file you wish to debug, and any
                        arguments to pass to it. To pass flags to the
                        binary, wrap in quotes, or use --args instead.
                        Example: gdbgui ./mybinary [other-gdbgui-args...]
                        Example: gdbgui './mybinary myarg -flag1 -flag2'
                        [other gdbgui args...] (default: None)

optional arguments:
  -h, --help            show this help message and exit
  --args ...            Specify the executable file you wish to debug and
                        any arguments to pass to it. All arguments are taken
                        literally, so if used, this must be the last
                        argument. This can also be specified later in the
                        frontend. passed to gdbgui. Example: gdbgui [...]
                        --args ./mybinary myarg -flag1 -flag2 (default: [])

gdb settings:
  -g GDB_CMD, --gdb-cmd GDB_CMD
                        gdb binary and arguments to run. If passing
                        arguments, enclose in quotes. If using rr, it should
                        be specified here with 'rr replay'. Examples: gdb,
                        /path/to/gdb, 'gdb --command=FILE -ix', 'rr replay'
                        (default: gdb)

gdbgui network settings:
  -p PORT, --port PORT  The port on which gdbgui will be hosted (default:
                        5000)
  --host HOST           The host ip address on which gdbgui serve (default:
                        127.0.0.1)
  -r, --remote          Shortcut to set host to 0.0.0.0 and suppress browser
                        from opening. This allows remote access to gdbgui
                        and is useful when running on a remote machine that
                        you want to view/debug from your local browser, or
                        let someone else debug your application remotely.
                        (default: False)

security settings:
  --auth-file AUTH_FILE
                        Require authentication before accessing gdbgui in
                        the browser. Specify a file that contains the HTTP
                        Basic auth username and password separate by
                        newline. (default: None)
  --user USER           Username when authenticating (default: None)
  --password PASSWORD   Password when authenticating (default: None)
  --key KEY             SSL private key. Generate with:openssl req -newkey
                        rsa:2048 -nodes -keyout host.key -x509 -days 365
                        -out host.cert (default: None)
  --cert CERT           SSL certificate. Generate with:openssl req -newkey
                        rsa:2048 -nodes -keyout host.key -x509 -days 365
                        -out host.cert (default: None)

other settings:
  --remap-sources REMAP_SOURCES, -m REMAP_SOURCES
                        Replace compile-time source paths to local source
                        paths. Pass valid JSON key/value pairs.i.e. --remap-
                        sources='{"/buildmachine": "/current/machine"}'
                        (default: None)
  --project PROJECT     Set the project directory. When viewing the
                        "folders" pane, paths are shown relative to this
                        directory. (default: None)
  -v, --version         Print version (default: False)
  -n, --no-browser      By default, the browser will open with gdbgui. Pass
                        this flag so the browser does not open. (default:
                        False)
  -b BROWSER, --browser BROWSER
                        Use the given browser executable instead of the
                        system default. (default: None)
  --debug               The debug flag of this Flask application. Pass this
                        flag when debugging gdbgui itself to automatically
                        reload the server when changes are detected
                        (default: False)
```


================================================
FILE: docs/contact.md
================================================
* Email: chadsmith.software@gmail.com

================================================
FILE: docs/examples.md
================================================

# Examples
## Code Examples
View code examples on [GitHub](https://github.com/cs01/gdbgui/tree/master/examples).

## gdbgui Invocation Examples

launch gdbgui

```
gdbgui
```

set the inferior program, pass argument, set a breakpoint at main

```
gdbgui --args ./myprogram myarg -myflag
```


```
gdbgui "./myprogram myarg -myflag"
```

use gdb binary not on your $PATH

```
gdbgui --gdb-cmd build/mygdb
```

Pass arbitrary arguments directly to gdb when it is launched

```
gdbgui --gdb-cmd="gdb -x gdbcmds.txt"
```

run on port 8080 instead of the default port

```
gdbgui --port 8080
```



run on a server and host on 0.0.0.0. Accessible to the outside world as long as port 80 is not blocked.

```
gdbgui -r
```

Same as previous but will prompt for a username and password

```
gdbgui -r --auth
```

Same as previous but with encrypted https connection.
```
openssl req -newkey rsa:2048 -nodes -keyout private.key -x509 -days 365 -out host.cert
```
```
gdbgui -r --auth --key private.key --cert host.cert
```

Use Mozilla's [record and replay](https://rr-project.org) (rr) debugging supplement to gdb. rr lets your record a program (usually with a hard-to-reproduce bug in it), then deterministically replay it as many times as you want. You can even step forwards and backwards.
```
gdbgui --gdb-cmd "rr replay --"
```

Use recording other than the most recent one

```
gdbgui --gdb-cmd "rr replay RECORDED_DIRECTORY --"
```

Don't automatically open the browser when launching

```
gdbgui -n
```


================================================
FILE: docs/faq.md
================================================
## How can I see what commands are being sent to gdb?
Go to Settings and check the box that says `Print all sent commands in console, including those sent automatically by gdbgui`

## How can I see gdb's raw output?
Launch gdbgui with the debug flag, `gdbgui --debug`, then a new component will appear on the bottom right side of UI.

## Can I use a different gdb executable?
Yes, use `gdbgui -g <gdb executable>`

## Does this work with LLDB?
No, only gdb.

## Can this debug Python?
No. It uses gdb on the backend which does not debug Python code.

## How do I make program output appear in a different terminal?
On linux terminals are named. You can get a terminal's name by running `tty` which will print something like `/dev/ttys3`. Tell gdb to use the terminal gdbgui was launched from with

```bash
gdbgui --gdb-args="--tty=$(tty)"
```

or if you want to set it from the UI after gdbgui has been opened, run

```bash
set inferior-tty /dev/ttys3  # replace /dev/ttys3 with desired tty name
```

## Help! There isn't a button for something I want to do. What should I do?
The vast majority of common use cases are handled in the UI, and to keep the UI somewhat simple I do not intend on making UI support for every single gdb command. You can search gdb documentation and use any gdb command you want in the console at the bottom of the window. If you think there should be a UI element for a command or function, create an issue on GitHub and I will consider it.


================================================
FILE: docs/gettingstarted.md
================================================
Before running `gdbgui`, you should compile your program with debug symbols and a lower level of optimization, so code isn't optimized out before runtime. To include debug symbols with `gcc` use `-ggdb`, with `rustc` use `-g`. To disable most optimizations in `gcc` use the `-O0` flag, with `rustc` use `-O`.

For more details, consult your compiler's documentation or a search engine.

Now that you have `gdbgui` installed and your program compiled with debug symbols, all you need to do is run
```
gdbgui
```

This will start gdbgui's server and open a new tab in your browser. That tab contains a fully functional frontend running `gdb`!

You can see gdbgui in action on [YouTube](https://www.youtube.com/channel/UCUCOSclB97r9nd54NpXMV5A).

To see the full list of options gdbgui offers, you can view command line options by running
```
gdbgui --help
```

If you have a question about something

* Read documentation on the [homepage](https://github.com/cs01/gdbgui/)
* [Ask question in an issue on github](https://github.com/cs01/gdbgui/issues)


## Settings
`gdbgui` settings can be accessed by clicking the gear icon in the top right of the frontend. Most of these settings persist between sessions for a given url and port.


## Keyboard Shortcuts
The following keyboard shortcuts are available when the focus is not in an input field. They have the same effect as when the button is pressed.

* Run: r
* Continue: c
* Next: n or right arrow
* Step: s or down arrow
* Up: u or up arrow
* Next Instruction: m
* Step Instruction: ,


================================================
FILE: docs/guides.md
================================================
gdb can be used in a plethora of environments. These guides help you get gdb and gdbgui working in specific environments.

Remember, these guides, like gdbgui, are **open source** and can be edited by you, the users! See [contributing](contributing) to modify these docs.

## Running Locally

After downloading gdbgui, you can launch it like so:

* `gdbgui` (or whatever the binary name is, i.e. `gdbgui_0.10.0.0`)
* `gdbgui --args ./mybinary -myarg value -flag1 -flag2`

Make sure the program you want to debug was compiled with debug symbols. See the getting started section for more details.

A new tab in your browser will open with gdbgui in it. If a browser tab did not open, navigate to the ip/port that gdbgui is being served on (i.e. http://localhost:5000).

Now that gdbgui is open, you can interactively run a program with it.
* Type the path to the executable in the input at the top (next to "Load Binary"). The executable should already exist and have been compiled with the `-g` flag.
* Click `Load Binary`. The program and symbols will load, but will not begin running. A breakpoint will be added to main automatically. This can be changed in settings if you prefer not to do this.
* The line of source code corresponding to main will display if the program was compiled with the `-g` flag debug symbols.
* Click the Run button, which is on the top right and looks like a circular arrow.
* Step through the program by clicking the Next, Step, Continue, icons as desired. These are also on the top right.

For a list of gdbgui arguments, run `gdbgui --help`.

## Running Remotely
Because gdbgui is a server, it naturally allows you to debug programs running on other computers.

* ssh into the computer with the program that needs to be debugged.
* run `gdbgui -r` on the remote machine (this will serve publicly so beware of security here)
* on your local machine, open your browser and access the remote machine's ip and port
* debug the remote computer in your local browser

Note that gnu also distrubutes a program called `gdbserver` which gdbgui is compatible with. See the relevant section in this doc.

## Debugging Rust Programs

`gdbgui` can be used to debug programs written in Rust. Assuming you use [Cargo](https://doc.rust-lang.org/stable/cargo/) to create a new program
and build it in Debug mode in the standard way:

```
cargo new myprog
cd myprog
cargo build
```

You can start debugging with

```
gdbgui --args target/debug/myprog
```

There are a couple of small difficulties.

1.) Instead of showing your `main` function the initial screen will be blank and `gdbgui` will print `File not found: main`.
You need to help `gdbgui` out by typing `main` into the file browser box:

![](https://raw.githubusercontent.com/cs01/gdbgui/master/screenshots/rust_main.png)

and selecting the `main.rs` file. The source code should then appear in the browser and you can click to set breakpoints
and run the program. Of course, if you want to break in some other file, you can find that in the file browser instead.

### Rust on macOS

When you load your rust binary on a mac, you may see many warnings like this

> warning /Users/user/examples/rust/target/debug/deps/hello-486956f9dde465e5.9elsx31vb4it187.rcgu.o': can't open to read symbols: No such file or directory.

Symbols are names of variables, functions and types defined in your program. You can define symbols for your program by loading symbol files. gdb usually does this automatically for you, but sometimes has trouble finding the right paths.

In this case, you need to manually tell gdb where the symbol files is; it's usually the first part of the missing file. In the above example, it's `hello-486956f9dde465e5.9elsx31vb4it187.rcgu.o`.

You can load this into gdb with the following command (changed as appropriate):

```
symbol-file /Users/user/git/gdbgui/examples/rust/target/debug/deps/hello-486956f9dde465e5
```

2.) The GDB pretty-printing macros that Rust ships with. GDB can't find these by default, which makes it print the message

```
warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts of file /home/temp/myprog/target/debug/myprog.
Use `info auto-load python-scripts [REGEXP]' to list them.
```

You can safely ignore this, but the [Rust issue](https://github.com/rust-lang/rust/issues/33159#issuecomment-384073290)
describes the workarounds necessary (create a `.gdbinit` file and paste a few lines into the Python helper script).

* On Windows Rust defaults to the MSVC toolchain, and `gdbgui` can't debug binaries compiled that way. If you want to use `gdbgui`, you'll have to [switch to the GNU toolchain](https://github.com/rust-lang-nursery/rustup.rs#working-with-rust-on-windows).
* If you want to debug programs compiled in Release mode, you will need to create a `profile.release` section in your
  `Cargo.toml` and add `debug = true` to it. See the [Cargo manifest](https://doc.rust-lang.org/stable/cargo/reference/manifest.html) for details.

and now gdb will be able to see which files were used to compile your binary, among other things.


## Connecting to gdbserver
Like gdb, [`gdbserver`](https://sourceware.org/gdb/onlinedocs/gdb/Server.html) is also made by gnu, but with the following important differences:

* it is much smaller than gdb
* it is easier to port to other architectures than all of gdb

gdbserver runs on a remote machine or embedded target, which, as the name suggests, runs a server. gdb communicates with gdbserver so you can debug on your local machine. To do this, the remote machine must run the server and program:

`gdbserver :9000 mybinary.a`

Then you can launch `gdb` or `gdbgui` and connect to it. In `gdbgui`, use the dropdown to select `Connect to gdbserver`, and enter

`<remote ip address>:9000`

Read more at the [gdbserver homepage](https://sourceware.org/gdb/onlinedocs/gdb/Server.html).

If the machine gdbgui is running on and the target being debugged have different architectures, make sure gdb is built properly (see `Remote Debugging Between Different Architectures`).

## Remote Debugging Between Different Architectures

For example, this is useful if you are working from an x86_64 based PC gdb client with gdbgui, to ARM arch gdbserver.

You need to build the `gdb` client with the `--host` and `--target` flags. You need to build the `gdbserver` for the correct architecture.

Build the `gdb` client that `gdbgui` will use. This example applies to an x86_64 pc running gdbgui that connects to an arm device running gdbserver, so you will need to ensure the targets apply to the environments you are working in:

1. downloaded latest gdb source code
2. unzip it, go into folder
3.
```bash
./configure  --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --target=arm-linux-gnuabi &&
make -j8 &&
sudo make install
```
4. Now arm-linux-gnuabi-gdb is installed by default to `/usr/local/bin`, but you can instead provide `prefix=<path>` to where you want it to install in the ./configure script above
5. The `arm-linux-gnuabi-gdb` binary can now be used by gdbgui to connect to the ARM device:

```bash
gdbgui -g arm-linux-gnuabi-gdb
```

Links:
* [Building GDB and GDBserver for cross debugging](https://sourceware.org/gdb/wiki/BuildingCrossGDBandGDBserver)
* [http://www.brain-dump.org/blog/entry/138/Cross_Arch_Remote_Debugging_with_gdb_and_gdbserver](Cross Arch Remote Debugging with gdb and gdbserver)
* [support remote debug from x86_64 based PC gdb client with gdbgui, to ARM arch gdbserver (multiarch)](https://github.com/cs01/gdbgui/issues/237)

================================================
FILE: docs/howitworks.md
================================================
gdbgui consists of two main parts: the frontend and the backend

## Backend

The backend is written in Python and consists of a Flask server with websocket capability thanks to the `python-socketio` package.

When a new websocket connection from a browser is established, the server starts a new gdb subprocess and associates it with this websocket. This gdb process is told to use gdb's [machine interface](https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI.html) interpreter, which enables gdb's input and output to be programatically parsed so you can write code to do further processing with it, such as build a user interface.

The [pygdbmi library](https://github.com/cs01/pygdbmi) is used to manage the gdb subprocess and parse its output. It returns key/value pairs (dictionaries) that can be used to create a frontend. I wrote pygdbmi as a building block for gdbgui, but it is useful for any type of programmatic control over gdb.

In summary, the backend is used to:

- create endpoints for the browser, including http and websocket.
  - The server can access the operating system and do things like read source files or send signals to processes.
- create a managed gdb subprocess and parse output with pygdbmi
- spawn a separate thread to constantly check for output from the gdb subprocess
- forward output to the client through a websocket as it is parsed in the reader thread

## Frontend

The frontend is written in JavaScript and uses React. It establishes a websocket connection to the server, at which time the server starts a new gdb subprocess for that particular websocket connection as mentioned above. Commands can be sent from the browser through the websocket to the server which writes to gdb, and output from gdb is forwarded from the server through the websocket to the browser.

As the browser receives websocket messages from the server, it maintains the state of gdb, such as whether it's running, paused, or exited, where breakpoints are, what the stack is, etc. As this state changes, React performs the necessary DOM updates.

In summary, the frontend is used to:

* Convert key/value pairs of gdb's machine interface output into a user interface
* Maintain the state of gdb
* Provide UI elements that can send gdb machine interface commands to gdb

================================================
FILE: docs/index.md
================================================
<p align="center">
<a href="http://gdbgui.com"><img src="https://github.com/cs01/gdbgui/raw/master/images/gdbgui_banner.png"></a>
</p>

<h3 align="center">
A browser-based frontend to gdb (gnu debugger)
</h3>

<p align="center">

<a href="https://github.com/cs01/gdbgui/actions">
<img src="https://github.com/cs01/gdbgui/workflows/Tests/badge.svg?branch=master" alt="CI Tests" /></a>

<a href="https://badge.fury.io/py/gdbgui">
<img src="https://badge.fury.io/py/gdbgui.svg" alt="PyPI version" >
</a>

<img src="https://pepy.tech/badge/gdbgui" alt="Download Count" />

</p>

---

<p align="center">
<a href="https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui_animation.gif">
<img src="https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui_animation.gif">
</a>

</p>

`gdbgui` is a browser-based frontend to `gdb`, the [gnu debugger](https://www.gnu.org/software/gdb/). You can add breakpoints, view stack traces, and more in C, C++, Go, and Rust!

It's perfect for beginners and experts. Simply run `gdbgui` from the terminal to start the gdbgui server, and a new tab will open in your browser.

**Sound Good? Get started with [installation](installation)**.

## Testimonials

"*Definitely worth checking out.*"

<div style="text-align: right; margin-right: 10%;">
—<a href="https://www.youtube.com/user/lefticus1">Jason Turner</a>, host of C++ weekly on <a href="https://www.youtube.com/watch?v=em842geJhfk">YouTube</a>
</div>

"_Seriously, great front-end to gdb for those of us who are not always using a full IDE. Great project._"

<div style="text-align: right; margin-right: 10%;">
—Jefferson on <a href="https://twitter.com/jeffamstutz/status/955647577373978624">Twitter</a>
</div>

"_Where were you all my life? And why did I use DDD?_"

<div style="text-align: right; margin-right: 10%;">
—<a href="https://github.com/badlogic">Mario Zechner</a>, author, game engine developer on <a href="https://twitter.com/badlogicgames/status/925079139446591490">Twitter</a>
</div>

gdbgui is used by thousands of developers around the world including engineers at Google and college computer science course instructions. It even made its way into the Rust programming language's [source code](https://github.com/rust-lang/rust/blob/master/src/etc/rust-gdbgui) and appeared on episode [110 of C++ Weekly](https://youtu.be/em842geJhfk).



## License

gdbgui's license is GNU GPLv3. To summarize it, you

- can use it for free at work or for personal use
- can modify its source code
- must disclose your source code if you redistribute any part of gdbgui

## Distribution

gdbgui is distributed through

- github ([https://github.com/cs01/gdbgui](https://github.com/cs01/gdbgui))
- [PyPI](https://pypi.python.org/pypi/gdbgui/)

## Authors

- Chad Smith, creator/maintainer
- @bobthekingofegypt, contibutor
- [Community contributions](https://github.com/cs01/gdbgui/graphs/contributors)

## Donate

[Paypal](https://www.paypal.me/grassfedcode/20)

## Contact

https://chadsmith.dev
chadsmith.software@gmail.com


================================================
FILE: docs/installation.md
================================================
# gdbgui installation

There are a few ways to install gdbgui on your machine. There is even a way to run gdbgui without installing it. Read on to to find the one that's right for you.

## Method 1: Using `pipx` (recommended)

gdbgui recommends using [pipx](https://github.com/pipxproject/pipx), a program to run Python CLI binaries in isolated environments.

You can install pipx like this:

```
python3 -m pip install --user pipx
python3 -m userpath append ~/.local/bin
```

Restart/re-source your console to make sure the userpath is up to date.

Then, install gdbgui with pipx:

```
pipx install gdbgui
```

To upgrade run

```
pipx upgrade gdbgui
```

When installation is finished, type `gdbgui` from the command line to run it, or `gdbgui -h` for help.

To uninstall, run

```
pipx uninstall gdbgui
```

### Try Without Installing

By using [pipx](https://github.com/pipxproject/pipx), you can run Python CLI programs in ephemeral one-time virtual environments.

```
pipx run gdbgui
```

A new tab running the latest version of gdbgui will open in your browser. Press CTRL+C to end the process, and your system will remain untouched.

## Method 2: Using `pip`

`pip` is a popular installer for Python packages. gdbgui is a Python package and as such can be installed with pip, though we recommend using `pipx` rather than `pip` if possible.

If you prefer to use Virtual Environments, you can activate one and then run

```
pip install gdbgui
```

You can get upgrades with

```
pip install --upgrade gdbgui
```

To uninstall, run

```
pip uninstall gdbgui
```

## Method 3: Download and Run Binary Executable

Download and run the binary executable for your system from [GitHub Releases](https://github.com/cs01/gdbgui/releases).

## System Dependencies for Python Package

Note that this only applies if you are installing the Python package, and not using the binary executable.

- gdb (gnu debugger)
- Python 3.4+ (recommended) or 2.7
- pip version 8 or higher

### Linux Dependencies

    sudo apt install gdb python3

### macOS Dependencies

    brew install python3
    brew install gdb --with-python --with-all-targets

macOS users must also codesign gdb: follow [these
instructions](http://andresabino.com/2015/04/14/codesign-gdb-on-mac-os-x-yosemite-10-10-2/). This will fix the error
`please check gdb is codesigned - see taskgated(8)`.

### Windows Dependencies

Note that windows is only supported for gdbgui versions less than 0.14.

- [Python 3](https://www.python.org/downloads/windows/)
- gdb, make, gcc

If you do not have already have gdb/make/gcc installed, there are two options to install them on Windows: `MinGW` and `cygwin`.

##### MinGW (recommended)

Minimal GNU for Windows ([`MinGW`]([http://mingw.org/)) is the recommended Windows option. [Install MinGW](https://sourceforge.net/projects/mingw/files/Installer/mingw-get-setup.exe/download) with the "MinGW Base System" package. This is the default package which contains `make`, `gcc`, and `gdb`.

It will install to somewhere like `C:\MinGW\bin\...`. For example `C:\MinGW\bin\gdb.exe`, `C:\MinGW\bin\mingw32-make.exe`, etc.

Ensure this MinGW binary directory (i.e. `C:\MinGW\bin\`) is on your "Path" environment variable: Go to `Control Panel > System Properties > Environment Variables > System Variables > Path` and make sure `C:\MinGW\bin\` is added to that list. If it is not added to your "Path", you will have to run gdbgui with the path explicitly called out, such as `gdbgui -g C:\MinGW\bin\gdb.exe`.

##### Cygwin

Cygwin is a more UNIX-like compatibility layer on Windows, and `gdbgui` works with it as well.

- Install [cygwin](https://cygwin.com/install.html)

When installing cygwin packages, add the following:

- python3
- python3-pip
- python3-devel
- gdb
- gcc-core
- gcc-g++

### Running from Source

See the [contributing](/contributing) section.


================================================
FILE: docs/screenshots.md
================================================
![image](https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui.png)
![image](https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui2.png)

Enter the binary and args just as you'd call them on the command line.
The binary is restored when gdbgui is opened at a later time.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/load_binary_and_args.png)

Intuitive control of your program. From left to right: Run, Continue,
Next, Step, Return, Next Instruction, Step Instruction.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/controls.png)

If the environment supports reverse debugging, such as when using an Intel CPU and running Linux and debugging with [rr](http://rr-project.org/), gdbgui allows you to debug in reverse.
![image](https://github.com/cs01/gdbgui/raw/master/screenshots/reverse_debugging.png)

## Stack/Threads

View all threads, the full stack on the active thread, the current frame
on inactive threads. Switch between frames on the stack, or threads by
pointing and clicking.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/stack_and_threads.png)

## Send Signal to Inferior (debugged) Process
Choose from any signal your OS supports to send to the inferior. For example, to mock `CTRL+C` in plain gdb, you can send `SIGINT` to interrupt the inferior process. If the inferior process is hung for some reason, you can send `SIGKILL`, etc.
![image](https://github.com/cs01/gdbgui/raw/master/screenshots/send_signal.png)


## Source Code
View source, assembly, add breakpoints. All symbols used to compile the
target are listed in a dropdown above the source code viewer, and have
autocompletion capabilities. There are two different color schemes: dark (monokai), and a light theme (default).

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/source.png)

With assembly. Note the bold line is the current instruction that gdb is
stopped on.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/source_with_assembly.png)

If the source file is not found, it will display assembly, and allow you to step through it as desired.
![image](https://github.com/cs01/gdbgui/raw/master/screenshots/assembly.png)


## Variables and Expressions

All local variables are automatically displayed, and are clickable to
explore their fields.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/locals.png)

Hover over a variable and explore it, just like in the Chrome debugger.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/hover.png)

Arbitrary expressions can be evaluated as well. These expressions persist as the program is stepped through. The base/radix can be modified as desired.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/radix.gif)

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/expressions.png)

Expressions record their previous values, and can be displayed in an x/y
plot.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/plots.png)

Expressions can be interactively explored in a tree view.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/tree_explorer.png)


## Memory Viewer

All hex addresses are automatically converted to clickable links to
explore memory. Length of memory is configurable. In this case 10 bytes
are displayed per row.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/memory.png)

## Registers

View all registers. If a register was updated it is highlighted in
yellow.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/registers.png)

## gdb console

* Prints gdb output
* Allows you to write directly to the underlying gdb subprocess as if you were using it in the terminal
* Tab completion works, and displays a button to view help on gdb commands
* Can be used to ease into learning gdb
* Can be used as a fallback for commands that don't have a UI widget
* History can be accessed using up/down arrows

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/console.png)

## authentication
Authentication can be enabled when serving on a publicly accessible IP address. See `gdbgui --help` for instructions on how to enable authentication.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/authentication.png)


## Dashboard
A dashboard is available to let you look at all gdb instances managed by gdbgui. You can kill them, or attach to them. More than one person can attach to a managed gdb subprocess and participate in the debugging session simultaneously. i.e. if one person steps forward, all connected users see the program step forward in real time.

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/dashboard.png)

## gdbgui at launch

![image](https://github.com/cs01/gdbgui/raw/master/screenshots/ready.png)


================================================
FILE: examples/.gitignore
================================================
*.a


================================================
FILE: examples/README.md
================================================
# Examples

## Overview
`gdbgui` can debug executables generated from various languages. This folder contains example source code and makefiles to build and automatically launch `gdbgui`.

## Clone
To get started, first clone this repository:
```
git clone https://github.com/cs01/gdbgui.git
```

## Install Dependencies
If you already installed `gdbgui` with `pip`, you have all dependencies installed. If not, you need to install them manually:
```bash
pip install -r gdbgui/requirements.txt  # run as sudo if this fails
```

## Build Executables and Debug with gdbgui
Enter the directory with the language of your choice in `gdbgui/examples/*` (`c`, `cpp`, `rust`, `golang`, `fortran`), then type `make` and hit the `tab` to see the make targets.

For example, in `gdbgui/examples/c`, running `make hello` will:

* build the binary (assuming you have the right compilers and libraries installed)
* open a new tab in your browser
* load the executable for the make target you just built
* insert a breakpoint at main (Rust and Go users may see machine code displayed rather than source code. This is a `gdb` limitation.)
* **Note: Although the program has loaded, you still must click the run icon to actually begin running the program.**


================================================
FILE: examples/c/debug_segfault.c
================================================
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    char* badstring = 0;
    const char* s = "gdbgui";

    int myvar = 100;
    unsigned int myvar2 = 200;

    printf("The next function call will cause a segfault. With gdbgui, the state of the program\n"
        "can be debugged at the time the program exited by running the command\n"
        "\"backtrace\" or \"bt\" in the gdb console.\n\n"
        "It will re-enter the state the\n"
        "program was in, including the stack trace: you'll end up in `main -> _IO_puts -> strlen`.\n"
        "If you click on the `main` function in the call stack, gdbgui will put you in the main function\n"
        "where you can inspect your local\n"
        "variables and determine how the segfault occured.\n\n"
        );


    printf("%s\n", badstring);

    printf("This line is never reached because the above line causes a segfault\n");
    return 0;
}


================================================
FILE: examples/c/hello.c
================================================
#include <stdio.h>
#include <string.h>
void say_something(const char *str)
{
  printf("%s\n", str);
}

struct mystruct_t
{
  int value;
  char letter;
  char *string;

  struct
  {
    double dbl;
  } substruct; /* named sub-struct */

  struct
  {
    float fp;
  }; /* anonymous struct */

  void *ptr;
  size_t struct_size;
  union {
    int unionint;
    double uniondouble;
  };
};

int main(int argc, char **argv)
{
  printf("Hello World\n");

  int retval = 1;

  /* bytes are allocated for s,
  but still contain garbage */
  struct mystruct_t s;
  s.value = 100;
  s.string = "pass";
  s.substruct.dbl = 567.8;
  s.letter = 'P';
  s.fp = 123.4;
  s.ptr = say_something;  /* address of function */
  s.ptr = &say_something; /* also address of function */
  s.unionint = 0;
  s.uniondouble = 1.0;

  for (int i = 0; i < 2; i++)
  {
    printf("i is %d\n", i);
  }

  if (!strcmp(s.string, "pass"))
  {
    retval = 0;
  }

  printf("returning %d\n", retval);
  say_something("Goodbye");
  return retval;
}


================================================
FILE: examples/c/input.c
================================================
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char name[20];
    printf("Hello. What's your name?\n");
    fgets(name, 20, stdin);
    printf("Hi there, %s", name);
    return 0;
}


================================================
FILE: examples/c/makefile
================================================
ROOT:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

hello: hello.c
	gcc hello.c -o hello_c.a -std=c99 -g
	@echo Run with gdbgui: gdbgui --args $(ROOT)/hello_c.a

input: input.c
	gcc input.c -o input.a -std=c99 -g
	@echo Run with gdbgui: gdbgui --args $(ROOT)/input.a

debug_segfault: debug_segfault.c
	gcc debug_segfault.c -g -o debug_segfault.a -std=c99
	@echo Run with gdbgui: gdbgui --args $(ROOT)/debug_segfault.a

threads: threads.c
	gcc threads.c -o threads.a -std=c99 -lpthread -g
	@echo Run with gdbgui: gdbgui --args $(ROOT)/threads.a

sleeper: sleeper.c
	gcc sleeper.c -o sleeper.a -std=c99 -g
	@echo Run with gdbgui: gdbgui --args $(ROOT)/sleeper.a


================================================
FILE: examples/c/sleeper.c
================================================
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv) {
  printf("entering\n");
  while(1){
    // while this loop is running, you cannot interact with
    // gdb until you interrupt (send signal SIGINT) to gdb
    // or the inferior process
    printf("sleeping...\n");
    sleep(2);
    printf("Finished sleeping. Repeating.\n");
  }
  printf("exiting\n");
  return 0;
}


================================================
FILE: examples/c/threads.c
================================================
#include <pthread.h>
#include <stdio.h>

static const int num_increments = 2;

/* this function is run by the second thread */
void *thread_callback(void *arg)
{
    int *val = (int*)arg;
    while((*val) < num_increments){
        printf("incrementing\n");
        (*val)++;
    }
    printf("increment finished\n");
}

int main()
{
    int x = 0, y = 0;
    printf("x: %d, y: %d\n", x, y);
    pthread_t thread_to_increment_x, thread_to_increment_y;

    /* create and run threads */
    if(pthread_create(&thread_to_increment_x, NULL, thread_callback, &x)) {
        printf("error: pthread_create returned non-zero value\n");
        return 1;
    }
    if(pthread_create(&thread_to_increment_y, NULL, thread_callback, &y)) {
        printf("error: pthread_create returned non-zero value\n");
        return 1;
    }

    /* wait for threads to finish */
    if(pthread_join(thread_to_increment_x, NULL)) {
        printf("error: pthread_join returned non-zero value\n");
        return 1;
    }
    if(pthread_join(thread_to_increment_y, NULL)) {
        printf("error: pthread_join returned non-zero value\n");
        return 1;
    }
    printf("x: %d, y: %d\n", x, y);

    return 0;

}


================================================
FILE: examples/c/tree.c
================================================
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

struct Node
{
    struct Node* left;
    struct Node* right;
    char* name;
};

void visit(struct Node* node)
{
    printf("visiting node '%s'\n", node->name);
}

void dfs(struct Node *node)
{
    if (node == NULL)
    {
        return;
    }

    visit(node);
    dfs(node->left);
    dfs(node->right);
}

int main(void)
{
    printf("gdbgui has a widget that allows interactive tree exploration. "
        "Enter 'root' in  'Expressions' widget, then hover over root and click the tree icon next to 'root' to draw the tree. "
        "The tree is automatically updated as the program's state changes changed.\n\n");
    /* initialize nodes so that left/right are NULL and each
    node has a name */
    struct Node
        root = {.name = "root"},
        a = {.name = "a"},
        b = {.name = "b"},
        c = {.name = "c"},
        d = {.name = "d"},
        e = {.name = "e"},
        f = {.name = "f"};

    /* connect nodes */
    printf("As you step through the following code, you can see the graph grow and change as assignments are made\n");
    root.left = &a;
    root.right = &b;
    a.left = &c;
    a.right = &d;
    d.left = &e;
    b.right = &f;

    printf("beginning depth first search. We can verify the dfs algorithm is accurate by comparing it to gdbgui's graph view.\n");
    dfs(&root);
    printf("finished depth first search\n");
    return 0;
}


================================================
FILE: examples/cpp/hello.cpp
================================================
#include <iostream>
#include <vector>
#include <map>

int main(void)
{
    std::cout << "Hello World" << std::endl;

    std::cout << "Example vector" << std::endl;
    std::vector<double> myvector {};
    myvector.push_back(1.1);
    myvector.push_back(2.2);
    myvector.push_back(3.3);
    myvector.push_back(4.4);
    for (auto i : myvector){
        std::cout << i << " is an element in a vector" << std::endl;
    }

    std::cout << "Example map" << std::endl;
    std::map<char,int> mymap;
    mymap['a'] = 10;
    mymap['b'] = 30;
    mymap['c'] = 50;
    mymap['d'] = 70;
    for (auto i : mymap){
        std::cout << i.first << " is a key in a map with a value of " << i.second << std::endl;
    }

    return 0;
}


================================================
FILE: examples/cpp/linked_list.cpp
================================================
#include <iostream>

class Node{

private:
    Node* next = 0;
    Node* prev = 0;
    int value;

public:
    Node(int v){
        value = v;
    }

    int get_value() const{
        return value;
    }

    void print_values() const{
        std::cout << this->get_value() << std::endl;
        if(this->next){
            this->next->print_values();
        }
    }

    void append(int v){
        Node* new_node = new Node(v);
        Node* iter = this;
        while(iter->next){
            iter = iter->next;
        }
        iter->next = new_node;
        new_node->prev = iter;
    }
};

int main(){
    Node* linked_list = new Node(0);
    linked_list->print_values();
    linked_list->append(1);
    linked_list->append(2);
    linked_list->append(3);
    linked_list->append(4);
    linked_list->print_values();
    return 0;
}


================================================
FILE: examples/cpp/makefile
================================================
GDBGUI=../../gdbgui/backend.py

hello: hello.cpp
	g++ hello.cpp -o hello_cpp.a -std=c++11 -g
	@echo Run with gdbgui: gdbgui --args hello_cpp.a

linked_list: linked_list.cpp
	g++ linked_list.cpp -o linked_list_cpp.a -std=c++11 -g
	@echo Run with gdbgui: gdbgui --args linked_list_cpp.a

smart_ptr_demo: smart_ptr_demo.cpp
	g++ smart_ptr_demo.cpp -o smart_ptr_demo_cpp.a -std=c++11 -g
	@echo Run with gdbgui: gdbgui --args smart_ptr_demo_cpp.a

sin: sin.cpp
	g++ sin.cpp -o sin_cpp.a -std=c++11 -g
	@echo Run with gdbgui: gdbgui --args sin_cpp.a


================================================
FILE: examples/cpp/sin.cpp
================================================
#include <math.h>       /* sin */

int main ()
{
  double angle = 0, result = 0;
  static const double RAD_TO_DEG = 3.14159265 / 180;
  while (angle <= 360){
    result = sin(angle * RAD_TO_DEG);
    angle += 20;
  }
  return 0;
}


================================================
FILE: examples/cpp/smart_ptr_demo.cpp
================================================
// A demonstration of unique, smart, weak, and raw pointers in C++11.
// compile with:
//  g++ smart_ptr_demo.cpp -std=c++11 -o smart_ptr_cpp_demo.a -g
//
// running yields:
// >> ./smart_ptr_demo_cpp.a
// constructed raw pointer, at address 0x169fc20
// entering local scope
// entered local scope
// constructed unique (only one reference) pointer, at address 0x16a0090
// constructed shared (local and global reference) pointer, at address 0x16a00f0
// constructed shared (one shared reference, two weak references) pointer, at address 0x16a0060
// local weak pointer has valid reference
// global weak pointer has valid reference
// smart pointers can be accessed like regular pointers
// This is my type: unique (only one reference)
// This is my type: shared (local and global reference)
// leaving local scope
// destroyed shared (one shared reference, two weak references) pointer, at address 0x16a0060
// destroyed unique (only one reference) pointer, at address 0x16a0090
// left local scope
// global weak pointer has no reference
// destroyed raw pointer, at address 0x169fc20
// leaving main
// destroyed shared (local and global reference) pointer, at address 0x16a00f0


#include <iostream>
#include <memory>
#include <string>

// A class that prints metadata when constructed and destroyed
class SimpleType
{
    std::string m_ptr_type;

public:
    SimpleType(const std::string& ptr_type){
        m_ptr_type = ptr_type;
        std::cout << "constructed " << m_ptr_type << " pointer, at address " << this << std::endl;
    }
    ~SimpleType(){
        std::cout << "destroyed " << m_ptr_type << " pointer, at address " << this << std::endl;
    }
    void identify(){
        std::cout << "This is my type: " << m_ptr_type << std::endl;
    }
};

int main()
{
    std::unique_ptr<SimpleType> globalunique;
    std::shared_ptr<SimpleType> globalshared;
    std::weak_ptr<SimpleType> globalweak;
    SimpleType* raw_ptr = new SimpleType("raw");

    // locally scoped operations will cause smart pointers to automatically
    // be deleted (garbage collected) if no owners remain at the end of the scope
    std::cout << "entering local scope" << std::endl;
    {
        std::cout << "entered local scope" << std::endl;
        // unique (deleted upon exit of this local scope)
        std::unique_ptr<SimpleType> localunique = std::unique_ptr<SimpleType>(new SimpleType("unique (only one reference)"));

        // shared with > 1 owner (not deleted upon exit of this local scope)
        std::shared_ptr<SimpleType> localshared = std::shared_ptr<SimpleType>(new SimpleType("shared (local and global reference)"));
        globalshared = localshared;  // assign global reference

        // shared with exactly 1 owner (deleted upon exit of this local scope)
        std::shared_ptr<SimpleType> localshared2 = std::shared_ptr<SimpleType>(new SimpleType("shared (one shared reference, two weak references)"));
        std::weak_ptr<SimpleType> localweak = localshared2;  // shared_ptr reference count does not increment here, because weak pointers don't "own" the pointer
        globalweak = localweak;  // again, the shared_ptr reference count does not increment
        // prove that the weak pointer references the shared pointer (but it does not own it!)
        std::cout << (localweak.lock() ? "local weak pointer has valid reference" : "local weak pointer has no reference") << std::endl;
        std::cout << (globalweak.lock() ? "global weak pointer has valid reference" : "global weak pointer has no reference") << std::endl;

        std::cout << "smart pointers can be accessed like regular pointers" << std::endl;
        localunique->identify();
        (*globalshared).identify();

        std::cout << "leaving local scope" << std::endl;
    } // localshared is not deleted here because the globalshared reference still exists and shares ownership of it.
      // localshared2/globalweak's object is deleted here. Even though globalweak still references it, it doesn't own it, so it's deleted.

    std::cout << "left local scope" << std::endl;
    std::cout << (globalweak.lock() ? "global weak pointer has valid reference" : "global weak pointer has no reference") << std::endl;
    delete raw_ptr;  // this needs to be done manually

    std::cout << "leaving main" << std::endl;
}


================================================
FILE: examples/fortran/fortran_array.f90
================================================
program array
  integer, parameter :: n=3
  integer :: ii
  real, dimension(n) :: a, b
  real, dimension(n,n) :: c

  a = [( real(ii), ii=1, n )]

  do ii = 1,n
    print *, a(ii)
  enddo

  b = 0.
  do ii = 1, n
    ! You could just write b = a ** 2., but I want to see the loop progress
    b(ii) = a(ii) ** 2.
  enddo

  do ii = 1, n
    print *, b(ii)
  enddo

  c = reshape( [( real(ii), ii=1,n**2 )], [n,n] )
  do ii = 1, n
    print *, c(ii,:)
  enddo

end program


================================================
FILE: examples/fortran/makefile
================================================
GDBGUI=../../gdbgui/backend.py

array_demo: fortran_array.f90
	gfortran fortran_array.f90 -o array_f90.a -g
	@echo Run with gdbgui: gdbgui --args array_f90.a


================================================
FILE: examples/golang/hello.go
================================================
package main
import "fmt"

func main() {
    fmt.Println("hello world")
    // Create an array of three ints.
    array := [...]int{10, 20, 30}

    // Loop over three ints and print them.
    for i := 0; i < len(array); i++ {
        fmt.Println(array[i])
    }
}


================================================
FILE: examples/golang/makefile
================================================
GDBGUI=../../gdbgui/backend.py

hello: hello.go
	go build -o hello_go.a -gccgoflags "-w" hello.go
	@echo Run with gdbgui: gdbgui --args hello_go.a


================================================
FILE: examples/rust/.gitignore
================================================
/target/
**/*.rs.bk

# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries


================================================
FILE: examples/rust/Cargo.toml
================================================
[package]
name = "hello"
version = "0.1.0"
authors = ["Your Name <YourName@example.com>"]

[dependencies]


================================================
FILE: examples/rust/README.md
================================================
This directory contains a very simple Rust program to demonstrate
how to run gdbgui.

Run the shell script `compile_and_debug.sh` which will use Cargo
to build the program in debug mode and then launch `gdbgui` to
debug the program.


================================================
FILE: examples/rust/compile_and_debug.sh
================================================
#!/usr/bin/env bash

GDBGUI=../../gdbgui/backend.py

cargo build && $GDBGUI ./target/debug/hello


================================================
FILE: examples/rust/src/main.rs
================================================
use std::mem;

// This function borrows a slice
fn analyze_slice(slice: &[i32]) {
    println!("first element of the slice: {}", slice[0]);
    println!("the slice has {} elements", slice.len());
}

fn main() {
    println!("Hello World!");
    // Fixed-size array (type signature is superfluous)
    let xs: [i32; 5] = [1, 2, 3, 4, 5];

    // All elements can be initialized to the same value
    let ys: [i32; 9] = [0; 9];

    // Indexing starts at 0
    println!("first element of the array: {}", xs[0]);
    println!("second element of the array: {}", xs[1]);

    // `len` returns the size of the array
    println!("array size: {}", xs.len());

    // Arrays are stack allocated
    println!("array occupies {} bytes", mem::size_of_val(&xs));

    // Arrays can be automatically borrowed as slices
    println!("borrow the whole array as a slice");
    analyze_slice(&xs);

    // Slices can point to a section of an array
    println!("borrow a section of the array as a slice");
    analyze_slice(&ys[1 .. 4]);
}


================================================
FILE: gdbgui/SSLify.py
================================================
"""Module to enable SSL for Flask application. Adapted from
https://github.com/kennethreitz/flask-sslify
"""

import os
import ssl

from flask import redirect, request

YEAR_IN_SECS = 31536000


class SSLify(object):
    """Secures your Flask App."""

    def __init__(
        self, app=None, age=YEAR_IN_SECS, subdomains=False, permanent=False, skips=None
    ):
        self.app = app
        self.hsts_age = age

        self.hsts_include_subdomains = subdomains
        self.permanent = permanent
        self.skip_list = skips

        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        """Configures the specified Flask app to enforce SSL."""
        app.config.setdefault("SSLIFY_SUBDOMAINS", False)
        app.config.setdefault("SSLIFY_PERMANENT", False)
        app.config.setdefault("SSLIFY_SKIPS", None)

        self.hsts_include_subdomains = (
            self.hsts_include_subdomains or app.config["SSLIFY_SUBDOMAINS"]
        )
        self.permanent = self.permanent or self.app.config["SSLIFY_PERMANENT"]
        self.skip_list = self.skip_list or self.app.config["SSLIFY_SKIPS"]

        app.before_request(self.redirect_to_ssl)
        app.after_request(self.set_hsts_header)

    @property
    def hsts_header(self):
        """Returns the proper HSTS policy."""
        hsts_policy = "max-age={0}".format(self.hsts_age)

        if self.hsts_include_subdomains:
            hsts_policy += "; includeSubDomains"

        return hsts_policy

    @property
    def skip(self):
        """Checks the skip list."""
        # Should we skip?
        if self.skip_list and isinstance(self.skip_list, list):
            for skip in self.skip_list:
                if request.path.startswith("/{0}".format(skip)):
                    return True
        return False

    def redirect_to_ssl(self):
        """Redirect incoming requests to HTTPS."""
        # Should we redirect?
        criteria = [
            request.is_secure,
            self.app.debug,
            self.app.testing,
            request.headers.get("X-Forwarded-Proto", "http") == "https",
        ]

        if not any(criteria) and not self.skip:
            if request.url.startswith("http://"):
                url = request.url.replace("http://", "https://", 1)
                code = 302
                if self.permanent:
                    code = 301
                r = redirect(url, code=code)
                return r

    def set_hsts_header(self, response):
        """Adds HSTS header to each response."""
        # Should we add STS header?
        if request.is_secure and not self.skip:
            response.headers.setdefault("Strict-Transport-Security", self.hsts_header)
        return response


def get_ssl_context(private_key, certificate):
    """Get ssl context from private key and certificate paths.
    The return value is used when calling Flask.
    i.e. app.run(ssl_context=get_ssl_context(,,,))
    """
    if (
        certificate
        and os.path.isfile(certificate)
        and private_key
        and os.path.isfile(private_key)
    ):
        context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
        context.load_cert_chain(certificate, private_key)
        return context
    return None


================================================
FILE: gdbgui/VERSION.txt
================================================
0.15.3.0


================================================
FILE: gdbgui/__init__.py
================================================
import io
import os
import sys

_base_dir = getattr(sys, "_MEIPASS", os.path.dirname(os.path.realpath(__file__)))
_version = (
    io.open(os.path.join(_base_dir, "VERSION.txt"), "r", encoding="utf-8")
    .read()
    .strip()
)

__title__ = "gdbgui"
__version__ = _version
__author__ = "Chad Smith"
__copyright__ = "Copyright Chad Smith"


================================================
FILE: gdbgui/__main__.py
================================================
from . import cli

cli.main()


================================================
FILE: gdbgui/cli.py
================================================
#!/usr/bin/env python

"""
A server that provides a graphical user interface to the gnu debugger (gdb).
https://github.com/cs01/gdbgui
"""

import argparse
import json
import logging
import os
import platform
import re
import shlex
from typing import List, Optional

from gdbgui import __version__
from gdbgui.server.app import app, socketio
from gdbgui.server.constants import DEFAULT_GDB_EXECUTABLE, DEFAULT_HOST, DEFAULT_PORT
from gdbgui.server.server import run_server


logger = logging.getLogger(__name__)
logging.getLogger("werkzeug").setLevel(logging.ERROR)


def get_gdbgui_auth_user_credentials(auth_file, user, password):
    if auth_file and (user or password):
        print("Cannot supply auth file and username/password")
        exit(1)
    if auth_file:
        if os.path.isfile(auth_file):
            with open(auth_file, "r") as authFile:
                data = authFile.read()
                split_file_contents = data.split("\n")
                if len(split_file_contents) < 2:
                    print(
                        'Auth file "%s" requires username on first line and password on second line'
                        % auth_file
                    )
                    exit(1)
                return split_file_contents

        else:
            print('Auth file "%s" for HTTP Basic auth not found' % auth_file)
            exit(1)
    elif user and password:
        return [user, password]

    else:
        return None


def warn_startup_with_shell_off(platform: str, gdb_args: str):
    """return True if user may need to turn shell off
    if mac OS version is 16 (sierra) or higher, may need to set shell off due
    to os's security requirements
    http://stackoverflow.com/questions/39702871/gdb-kind-of-doesnt-work-on-macos-sierra
    """
    darwin_match = re.match(r"darwin-(\d+)\..*", platform)
    on_darwin = darwin_match is not None and int(darwin_match.groups()[0]) >= 16
    if on_darwin:
        shell_is_off = "startup-with-shell off" in gdb_args
        return not shell_is_off
    return False


def get_parser():
    parser = argparse.ArgumentParser(
        description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )

    gdb_group = parser.add_argument_group(title="gdb settings")
    args_group = parser.add_mutually_exclusive_group()
    network = parser.add_argument_group(title="gdbgui network settings")
    security = parser.add_argument_group(title="security settings")
    other = parser.add_argument_group(title="other settings")

    gdb_group.add_argument(
        "-g",
        "--gdb-cmd",
        help="""
        gdb binary and arguments to run. If passing arguments,
        enclose in quotes.
        If using rr, it should be specified here with
        'rr replay'.
        Examples: gdb, /path/to/gdb, 'gdb --command=FILE -ix', 'rr replay'

        """,
        default=DEFAULT_GDB_EXECUTABLE,
    )
    network.add_argument(
        "-p",
        "--port",
        help="The port on which gdbgui will be hosted",
        default=DEFAULT_PORT,
    )
    network.add_argument(
        "--host", help="The host ip address on which gdbgui serve", default=DEFAULT_HOST
    )
    network.add_argument(
        "-r",
        "--remote",
        help="Shortcut to set host to 0.0.0.0 and suppress browser from opening. This allows remote access "
        "to gdbgui and is useful when running on a remote machine that you want to view/debug from your local "
        "browser, or let someone else debug your application remotely.",
        action="store_true",
    )

    security.add_argument(
        "--auth-file",
        help="Require authentication before accessing gdbgui in the browser. "
        "Specify a file that contains the HTTP Basic auth username and password separate by newline. ",
    )

    security.add_argument("--user", help="Username when authenticating")
    security.add_argument("--password", help="Password when authenticating")
    security.add_argument(
        "--key",
        default=None,
        help="SSL private key. "
        "Generate with:"
        "openssl req -newkey rsa:2048 -nodes -keyout host.key -x509 -days 365 -out host.cert",
    )
    # https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs
    security.add_argument(
        "--cert",
        default=None,
        help="SSL certificate. "
        "Generate with:"
        "openssl req -newkey rsa:2048 -nodes -keyout host.key -x509 -days 365 -out host.cert",
    )
    # https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs

    other.add_argument(
        "--remap-sources",
        "-m",
        help=(
            "Replace compile-time source paths to local source paths. "
            "Pass valid JSON key/value pairs."
            'i.e. --remap-sources=\'{"/buildmachine": "/current/machine"}\''
        ),
    )
    other.add_argument(
        "--project",
        help='Set the project directory. When viewing the "folders" pane, paths are shown relative to this directory.',
    )
    other.add_argument("-v", "--version", help="Print version", action="store_true")

    other.add_argument(
        "-n",
        "--no-browser",
        help="By default, the browser will open with gdbgui. Pass this flag so the browser does not open.",
        action="store_true",
    )
    other.add_argument(
        "-b",
        "--browser",
        help="Use the given browser executable instead of the system default.",
        default=None,
    )
    other.add_argument(
        "--debug",
        help="The debug flag of this Flask application. "
        "Pass this flag when debugging gdbgui itself to automatically reload the server when changes are detected",
        action="store_true",
    )
    args_group.add_argument(
        "debug_program",
        nargs="?",
        help="The executable file you wish to debug, and any arguments to pass to it."
        " To pass flags to the binary, wrap in quotes, or use --args instead."
        " Example: gdbgui ./mybinary [other-gdbgui-args...]"
        " Example: gdbgui './mybinary myarg -flag1 -flag2' [other gdbgui args...]",
        default=None,
    )
    args_group.add_argument(
        "--args",
        nargs=argparse.REMAINDER,
        help="Specify the executable file you wish to debug and any arguments to pass to it. All arguments are"
        " taken literally, so if used, this must be the last argument. This can also be specified later in the frontend."
        " passed to gdbgui."
        " Example: gdbgui [...] --args ./mybinary myarg -flag1 -flag2",
        default=[],
    )
    return parser


def get_initial_binary_and_args(
    user_supplied_args: List[str], debug_program_and_args: Optional[str]
) -> List[str]:
    if debug_program_and_args:
        # passed via positional
        return shlex.split(debug_program_and_args)
    else:
        # passed via --args
        return user_supplied_args


def main():
    """Entry point from command line"""
    parser = get_parser()
    args = parser.parse_args()
    if args.version:
        print(__version__)
        return

    if args.no_browser and args.browser:
        print("Cannot specify no-browser and browser. Must specify one or the other.")
        exit(1)

    app.config["gdb_command"] = args.gdb_cmd
    app.config["initial_binary_and_args"] = get_initial_binary_and_args(
        args.args, args.debug_program
    )
    app.config["gdbgui_auth_user_credentials"] = get_gdbgui_auth_user_credentials(
        args.auth_file, args.user, args.password
    )
    app.config["project_home"] = args.project
    if args.remap_sources:
        try:
            app.config["remap_sources"] = json.loads(args.remap_sources)
        except json.decoder.JSONDecodeError as e:
            print(
                "The '--remap-sources' argument must be valid JSON. See gdbgui --help."
            )
            print(e)
            exit(1)

    if args.remote:
        args.host = "0.0.0.0"
        args.no_browser = True
        if app.config["gdbgui_auth_user_credentials"] is None:
            print(
                "Warning: authentication is recommended when serving on a publicly "
                "accessible IP address. See gdbgui --help."
            )

    if warn_startup_with_shell_off(platform.platform().lower(), args.gdb_cmd):
        logger.warning(
            "You may need to set startup-with-shell off when running on a mac. i.e.\n"
            "  gdbgui --gdb-cmd='gdb --init-eval-command=\"set startup-with-shell off\"'\n"
            "see http://stackoverflow.com/questions/39702871/gdb-kind-of-doesnt-work-on-macos-sierra\n"
            "and https://sourceware.org/gdb/onlinedocs/gdb/Starting.html"
        )

    logger.setLevel(logging.DEBUG if args.debug else logging.INFO)

    run_server(
        app=app,
        socketio=socketio,
        host=args.host,
        port=int(args.port),
        debug=bool(args.debug),
        open_browser=(not args.no_browser),
        browsername=args.browser,
        private_key=args.key,
        certificate=args.cert,
    )


if __name__ == "__main__":
    main()


================================================
FILE: gdbgui/htmllistformatter.py
================================================
from pygments.formatters import HtmlFormatter  # type: ignore


class HtmlListFormatter(HtmlFormatter):
    """A custom pygments class to format html. Returns a list of source code.
    Each element of the list corresponds to a line of (marked up) source code.
    """

    def get_marked_up_list(self, tokensource):
        """an updated version of pygments.formatter.format_unencoded"""
        source = self._format_lines(tokensource)
        if self.hl_lines:
            source = self._highlight_lines(source)
        if not self.nowrap:
            if self.linenos == 2:
                source = self._wrap_inlinelinenos(source)
            if self.lineanchors:
                source = self._wrap_lineanchors(source)
            if self.linespans:
                source = self._wrap_linespans(source)
            if self.linenos == 1:
                source = self._wrap_tablelinenos(source)
        # instead of this:
        # for t, piece in source:
        #     outfile.write(piece)
        # evaluate the generator to a list of just source code:
        IS_CODE_INDEX = 0
        HTML_VALUE_INDEX = 1
        IS_CODE_VAL = 1
        source_list = [
            html_line[HTML_VALUE_INDEX]
            for html_line in self._wrap_div(self._wrap_pre(source))
            if html_line[IS_CODE_INDEX] == IS_CODE_VAL
        ]
        return source_list


================================================
FILE: gdbgui/py.typed
================================================
# Marker file for PEP 561.  This package uses inline types.
# https://mypy.readthedocs.io/en/latest/installed_packages.html#making-pep-561-compatible-packages

================================================
FILE: gdbgui/server/__init__.py
================================================


================================================
FILE: gdbgui/server/app.py
================================================
import binascii
import logging
import os
from typing import Dict, List
import traceback
from flask import Flask, abort, request, session
from flask_compress import Compress  # type: ignore
from flask_socketio import SocketIO, emit  # type: ignore

from .constants import DEFAULT_GDB_EXECUTABLE, STATIC_DIR, TEMPLATE_DIR
from .http_routes import blueprint
from .http_util import is_cross_origin
from .sessionmanager import SessionManager, DebugSession

logger = logging.getLogger(__file__)
# Create flask application and add some configuration keys to be used in various callbacks
app = Flask(__name__, template_folder=str(TEMPLATE_DIR), static_folder=str(STATIC_DIR))
Compress(
    app
)  # add gzip compression to Flask. see https://github.com/libwilliam/flask-compress
app.register_blueprint(blueprint)
app.config["initial_binary_and_args"] = []
app.config["gdb_path"] = DEFAULT_GDB_EXECUTABLE
app.config["gdb_command"] = None
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.config["project_home"] = None
app.config["remap_sources"] = {}
manager = SessionManager()
app.config["_manager"] = manager
app.secret_key = binascii.hexlify(os.urandom(24)).decode("utf-8")
socketio = SocketIO(manage_session=False)


@app.before_request
def csrf_protect_all_post_and_cross_origin_requests():
    """returns None upon success"""
    success = None
    if is_cross_origin(request):
        logger.warning("Received cross origin request. Aborting")
        abort(403)
    if request.method in ["POST", "PUT"]:
        server_token = session.get("csrf_token")
        if server_token == request.form.get("csrf_token"):
            return success
        elif server_token == request.environ.get("HTTP_X_CSRFTOKEN"):
            return success
        elif request.json and server_token == request.json.get("csrf_token"):
            return success
        else:
            logger.warning("Received invalid csrf token. Aborting")
            abort(403)


@socketio.on("connect", namespace="/gdb_listener")
def client_connected():
    """Connect a websocket client to a debug session

    This is the main intial connection.

    Depending on the arguments passed, the client will connect
    to an existing debug session, or create a new one.
    A message is a emitted back to the client with details on
    the debug session that was created or connected to.
    """
    if is_cross_origin(request):
        logger.warning("Received cross origin request. Aborting")
        abort(403)

    csrf_token = request.args.get("csrf_token")
    if csrf_token is None:
        logger.warning("Recieved invalid csrf token")
        emit("server_error", {"message": "Recieved invalid csrf token"})
        return

    elif csrf_token != session.get("csrf_token"):
        # this can happen fairly often, so log debug message, not warning
        logger.debug(
            "Recieved invalid csrf token %s (expected %s)"
            % (csrf_token, str(session.get("csrf_token")))
        )
        emit(
            "server_error", {"message": "Session expired. Please refresh this webpage."}
        )
        return

    desired_gdbpid = int(request.args.get("gdbpid", 0))
    try:
        if desired_gdbpid:
            # connect to exiting debug session
            debug_session = manager.connect_client_to_debug_session(
                desired_gdbpid=desired_gdbpid, client_id=request.sid
            )
            emit(
                "debug_session_connection_event",
                {
                    "ok": True,
                    "started_new_gdb_process": False,
                    "pid": debug_session.pid,
                    "message": f"Connected to existing gdb process {desired_gdbpid}",
                },
            )
        else:
            # start new debug session
            gdb_command = request.args.get("gdb_command", app.config["gdb_command"])
            mi_version = request.args.get("mi_version", "mi2")
            debug_session = manager.add_new_debug_session(
                gdb_command=gdb_command, mi_version=mi_version, client_id=request.sid
            )
            emit(
                "debug_session_connection_event",
                {
                    "ok": True,
                    "started_new_gdb_process": True,
                    "message": f"Started new gdb process, pid {debug_session.pid}",
                    "pid": debug_session.pid,
                },
            )
    except Exception as e:
        emit(
            "debug_session_connection_event",
            {"message": f"Failed to establish gdb session: {e}", "ok": False},
        )

    # Make sure there is a reader thread reading. One thread reads all instances.
    if manager.gdb_reader_thread is None:
        manager.gdb_reader_thread = socketio.start_background_task(
            target=read_and_forward_gdb_and_pty_output
        )
        logger.info("Created background thread to read gdb responses")


@socketio.on("pty_interaction", namespace="/gdb_listener")
def pty_interaction(message):
    """Write a character to the user facing pty"""
    debug_session = manager.debug_session_from_client_id(request.sid)
    if not debug_session:
        emit(
            "error_running_gdb_command",
            {"message": f"no gdb session available for client id {request.sid}"},
        )
        return

    try:
        data = message.get("data")
        pty_name = data.get("pty_name")
        if pty_name == "user_pty":
            pty = debug_session.pty_for_gdb
        elif pty_name == "program_pty":
            pty = debug_session.pty_for_debugged_program
        else:
            raise ValueError(f"Unknown pty: {pty_name}")

        action = data.get("action")
        if action == "write":
            key = data["key"]
            pty.write(key)
        elif action == "set_winsize":
            pty.set_winsize(data["rows"], data["cols"])
        else:
            raise ValueError(f"Unknown action {action}")
    except Exception:
        err = traceback.format_exc()
        logger.error(err)
        emit("error_running_gdb_command", {"message": err})


@socketio.on("run_gdb_command", namespace="/gdb_listener")
def run_gdb_command(message: Dict[str, str]):
    """Write commands to gdbgui's gdb mi pty"""
    client_id = request.sid  # type: ignore
    debug_session = manager.debug_session_from_client_id(client_id)
    if not debug_session:
        emit("error_running_gdb_command", {"message": "no session"})
        return
    pty_mi = debug_session.pygdbmi_controller
    if pty_mi is not None:
        try:
            # the command (string) or commands (list) to run
            cmds = message["cmd"]
            for cmd in cmds:
                pty_mi.write(
                    cmd + "\n",
                    timeout_sec=0,
                    raise_error_on_timeout=False,
                    read_response=False,
                )

        except Exception:
            err = traceback.format_exc()
            logger.error(err)
            emit("error_running_gdb_command", {"message": err})
    else:
        emit("error_running_gdb_command", {"message": "gdb is not running"})


def send_msg_to_clients(client_ids, msg, error=False):
    """Send message to all clients"""
    if error:
        stream = "stderr"
    else:
        stream = "stdout"

    response = [{"message": None, "type": "console", "payload": msg, "stream": stream}]

    for client_id in client_ids:
        logger.info("emiting message to websocket client id " + client_id)
        socketio.emit(
            "gdb_response", response, namespace="/gdb_listener", room=client_id
        )


@socketio.on("disconnect", namespace="/gdb_listener")
def client_disconnected():
    """do nothing if client disconnects"""
    manager.disconnect_client(request.sid)
    logger.info("Client websocket disconnected, id %s" % (request.sid))


@socketio.on("Client disconnected")
def test_disconnect():
    print("Client websocket disconnected", request.sid)


def read_and_forward_gdb_and_pty_output():
    """A task that runs on a different thread, and emits websocket messages
    of gdb responses"""

    while True:
        socketio.sleep(0.05)
        debug_sessions_to_remove = []
        for debug_session, client_ids in manager.debug_session_to_client_ids.items():
            try:
                try:
                    response = debug_session.pygdbmi_controller.get_gdb_response(
                        timeout_sec=0, raise_error_on_timeout=False
                    )

                except Exception:
                    response = None
                    send_msg_to_clients(
                        client_ids,
                        "The underlying gdb process has been killed. This tab will no longer function as expected.",
                        error=True,
                    )
                    debug_sessions_to_remove.append(debug_session)

                if response:
                    for client_id in client_ids:
                        logger.info(
                            "emiting message to websocket client id " + client_id
                        )
                        socketio.emit(
                            "gdb_response",
                            response,
                            namespace="/gdb_listener",
                            room=client_id,
                        )
                else:
                    # there was no queued response from gdb, not a problem
                    pass

            except Exception:
                logger.error("caught exception, continuing:" + traceback.format_exc())

        debug_sessions_to_remove += check_and_forward_pty_output()
        for debug_session in set(debug_sessions_to_remove):
            manager.remove_debug_session(debug_session)


def check_and_forward_pty_output() -> List[DebugSession]:
    debug_sessions_to_remove = []
    for debug_session, client_ids in manager.debug_session_to_client_ids.items():
        try:
            response = debug_session.pty_for_gdb.read()
            if response is not None:
                for client_id in client_ids:
                    socketio.emit(
                        "user_pty_response",
                        response,
                        namespace="/gdb_listener",
                        room=client_id,
                    )

            response = debug_session.pty_for_debugged_program.read()
            if response is not None:
                for client_id in client_ids:
                    socketio.emit(
                        "program_pty_response",
                        response,
                        namespace="/gdb_listener",
                        room=client_id,
                    )
        except Exception as e:
            debug_sessions_to_remove.append(debug_session)
            for client_id in client_ids:
                socketio.emit(
                    "fatal_server_error",
                    {"message": str(e)},
                    namespace="/gdb_listener",
                    room=client_id,
                )
            logger.error(e, exc_info=True)
    return debug_sessions_to_remove


================================================
FILE: gdbgui/server/constants.py
================================================
import os
import signal
import sys
from pathlib import Path

DEFAULT_GDB_EXECUTABLE = "gdb"
DEFAULT_HOST = "127.0.0.1"
DEFAULT_PORT = 5000
USING_WINDOWS = os.name == "nt"
IS_A_TTY = sys.stdout.isatty()
pyinstaller_base_dir = getattr(sys, "_MEIPASS", None)
using_pyinstaller = pyinstaller_base_dir is not None
if using_pyinstaller:
    BASE_PATH = Path(pyinstaller_base_dir or "")
else:
    BASE_PATH = Path(os.path.realpath(__file__)).parent.parent
    PARENTDIR = BASE_PATH.parent
    sys.path.append(str(PARENTDIR))

TEMPLATE_DIR = BASE_PATH / "templates"
STATIC_DIR = BASE_PATH / "static"


def colorize(text):
    if IS_A_TTY and not USING_WINDOWS:
        return "\033[1;32m" + text + "\x1b[0m"

    else:
        return text


# create dictionary of signal names
SIGNAL_NAME_TO_OBJ = {}
for n in dir(signal):
    if n.startswith("SIG") and "_" not in n:
        SIGNAL_NAME_TO_OBJ[n.upper()] = getattr(signal, n)


================================================
FILE: gdbgui/server/http_routes.py
================================================
import json
import logging
import os

from flask import (
    Blueprint,
    current_app,
    jsonify,
    redirect,
    render_template,
    request,
    session,
    Response,
)
from pygments.lexers import get_lexer_for_filename  # type: ignore

from gdbgui import htmllistformatter, __version__

from .constants import TEMPLATE_DIR, USING_WINDOWS, SIGNAL_NAME_TO_OBJ
from .http_util import (
    add_csrf_token_to_session,
    authenticate,
    client_error,
    csrf_protect,
)

logger = logging.getLogger(__file__)
blueprint = Blueprint("http_routes", __name__, template_folder=str(TEMPLATE_DIR))


@blueprint.route("/read_file", methods=["GET"])
@csrf_protect
def read_file():
    """Read a file and return its contents as an array"""

    def should_highlight():
        try:
            return json.loads(request.args.get("highlight", "true"))
        except Exception as e:
            if current_app.debug:
                print("Raising exception since debug is on")
                raise e

            else:
                return True  # highlight argument was invalid for some reason, default to true

    path = request.args.get("path")
    start_line = int(request.args.get("start_line"))
    start_line = max(1, start_line)  # make sure it's not negative
    end_line = int(request.args.get("end_line"))

    if path and os.path.isfile(path):
        try:
            last_modified = os.path.getmtime(path)
            with open(path, "r") as f:
                raw_source_code_list = f.read().split("\n")
                num_lines_in_file = len(raw_source_code_list)
                end_line = min(
                    num_lines_in_file, end_line
                )  # make sure we don't try to go too far

                # if leading lines are '', then the lexer will strip them out, but we want
                # to preserve blank lines. Insert a space whenever we find a blank line.
                for i in range((start_line - 1), (end_line)):
                    if raw_source_code_list[i] == "":
                        raw_source_code_list[i] = " "
                raw_source_code_lines_of_interest = raw_source_code_list[
                    (start_line - 1) : (end_line)
                ]
            try:
                lexer = get_lexer_for_filename(path)
            except Exception:
                lexer = None

            if lexer and should_highlight():
                highlighted = True
                # convert string into tokens
                tokens = lexer.get_tokens("\n".join(raw_source_code_lines_of_interest))
                # format tokens into nice, marked up list of html
                formatter = (
                    htmllistformatter.HtmlListFormatter()
                )  # Don't add newlines after each line
                source_code = formatter.get_marked_up_list(tokens)
            else:
                highlighted = False
                source_code = raw_source_code_lines_of_interest

            return jsonify(
                {
                    "source_code_array": source_code,
                    "path": path,
                    "last_modified_unix_sec": last_modified,
                    "highlighted": highlighted,
                    "start_line": start_line,
                    "end_line": end_line,
                    "num_lines_in_file": num_lines_in_file,
                }
            )

        except Exception as e:
            return client_error({"message": "%s" % e})

    else:
        return client_error({"message": "File not found: %s" % path})


@blueprint.route("/get_last_modified_unix_sec", methods=["GET"])
@csrf_protect
def get_last_modified_unix_sec():
    """Get last modified unix time for a given file"""
    path = request.args.get("path")
    if path and os.path.isfile(path):
        try:
            last_modified = os.path.getmtime(path)
            return jsonify({"path": path, "last_modified_unix_sec": last_modified})

        except Exception as e:
            return client_error({"message": "%s" % e, "path": path})

    else:
        return client_error({"message": "File not found: %s" % path, "path": path})


@blueprint.route("/help")
def help_route():
    return redirect("https://github.com/cs01/gdbgui/blob/master/HELP.md")


@blueprint.route("/dashboard", methods=["GET"])
@authenticate
def dashboard():
    manager = current_app.config.get("_manager")

    add_csrf_token_to_session()

    """display a dashboard with a list of all running gdb processes
    and ability to kill them, or open a new tab to work with that
    GdbController instance"""
    return render_template(
        "dashboard.html",
        gdbgui_sessions=manager.get_dashboard_data(),
        csrf_token=session["csrf_token"],
        default_command=current_app.config["gdb_command"],
    )


@blueprint.route("/", methods=["GET"])
@authenticate
def gdbgui():
    """Render the main gdbgui interface"""
    gdbpid = request.args.get("gdbpid", 0)
    gdb_command = request.args.get("gdb_command", current_app.config["gdb_command"])
    add_csrf_token_to_session()

    THEMES = ["monokai", "light"]
    initial_data = {
        "csrf_token": session["csrf_token"],
        "gdbgui_version": __version__,
        "gdbpid": gdbpid,
        "gdb_command": gdb_command,
        "initial_binary_and_args": current_app.config["initial_binary_and_args"],
        "project_home": current_app.config["project_home"],
        "remap_sources": current_app.config["remap_sources"],
        "themes": THEMES,
        "signals": SIGNAL_NAME_TO_OBJ,
        "using_windows": USING_WINDOWS,
    }

    return render_template(
        "gdbgui.html",
        version=__version__,
        debug=current_app.debug,
        initial_data=initial_data,
        themes=THEMES,
    )


@blueprint.route("/dashboard_data", methods=["GET"])
@authenticate
def dashboard_data():
    manager = current_app.config.get("_manager")

    return jsonify(manager.get_dashboard_data())


@blueprint.route("/kill_session", methods=["PUT"])
@authenticate
def kill_session():
    from .app import manager

    pid = request.json.get("gdbpid")
    if pid:
        manager.remove_debug_session_by_pid(pid)
        return jsonify({"success": True})
    else:
        return Response(
            "Missing required parameter: gdbpid",
            401,
        )


@blueprint.route("/send_signal_to_pid", methods=["POST"])
def send_signal_to_pid():
    signal_name = request.form.get("signal_name", "").upper()
    pid_str = str(request.form.get("pid"))
    try:
        pid_int = int(pid_str)
    except ValueError:
        return (
            jsonify(
                {
                    "message": "The pid %s cannot be converted to an integer. Signal %s was not sent."
                    % (pid_str, signal_name)
                }
            ),
            400,
        )

    if signal_name not in SIGNAL_NAME_TO_OBJ:
        raise ValueError("no such signal %s" % signal_name)
    signal_value = int(SIGNAL_NAME_TO_OBJ[signal_name])

    try:
        os.kill(pid_int, signal_value)
    except Exception:
        return (
            jsonify(
                {
                    "message": "Process could not be killed. Is %s an active PID?"
                    % pid_int
                }
            ),
            400,
        )
    return jsonify(
        {
            "message": "sent signal %s (%s) to process id %s"
            % (signal_name, signal_value, pid_str)
        }
    )


================================================
FILE: gdbgui/server/http_util.py
================================================
import binascii
import logging
import os
from functools import wraps

from flask import Response, abort, current_app, jsonify, request, session

logger = logging.getLogger(__file__)


def add_csrf_token_to_session():
    if "csrf_token" not in session:
        session["csrf_token"] = binascii.hexlify(os.urandom(20)).decode("utf-8")


def is_cross_origin(request):
    """Compare headers HOST and ORIGIN. Remove protocol prefix from ORIGIN, then
    compare. Return true if they are not equal
    example HTTP_HOST: '127.0.0.1:5000'
    example HTTP_ORIGIN: 'http://127.0.0.1:5000'
    """
    origin = request.environ.get("HTTP_ORIGIN")
    host = request.environ.get("HTTP_HOST")
    if origin is None:
        # origin is sometimes omitted by the browser when origin and host are equal
        return False

    if origin.startswith("http://"):
        origin = origin.replace("http://", "")
    elif origin.startswith("https://"):
        origin = origin.replace("https://", "")
    return host != origin


def csrf_protect(f):
    """A decorator to add csrf protection by validing the X_CSRFTOKEN
    field in request header"""

    @wraps(f)
    def wrapper(*args, **kwargs):
        token = session.get("csrf_token", None)
        if token is None or token != request.environ.get("HTTP_X_CSRFTOKEN"):
            logger.warning("Received invalid csrf token. Aborting")
            abort(403)
        # call original request handler
        return f(*args, **kwargs)

    return wrapper


def client_error(obj):
    return jsonify(obj), 400


def authenticate(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        if current_app.config.get("gdbgui_auth_user_credentials") is not None:
            auth = request.authorization
            if (
                not auth
                or not auth.username
                or not auth.password
                or not credentials_are_valid(auth.username, auth.password)
            ):
                return Response(
                    "You must log in to continue.",
                    401,
                    {"WWW-Authenticate": 'Basic realm="gdbgui_login"'},
                )

        return f(*args, **kwargs)

    return wrapper


def credentials_are_valid(username, password):
    user_credentials = current_app.config.get("gdbgui_auth_user_credentials")
    if user_credentials is None:
        return False

    elif len(user_credentials) < 2:
        return False

    return user_credentials[0] == username and user_credentials[1] == password


================================================
FILE: gdbgui/server/ptylib.py
================================================
import os

USING_WINDOWS = os.name == "nt"
if USING_WINDOWS:
    raise RuntimeError(
        "Windows is not supported at this time. "
        + "Versions lower than 0.14.x. are Windows compatible."
    )
import fcntl
import pty
import select
import shlex
import signal
import struct
import termios
from typing import Optional


class Pty:
    max_read_bytes = 1024 * 20

    def __init__(self, *, cmd: Optional[str] = None, echo: bool = True):
        if cmd:
            (child_pid, fd) = pty.fork()
            if child_pid == 0:
                # this is the child process fork.
                # anything printed here will show up in the pty, including the output
                # of this subprocess
                def sigint_handler(_sig, _frame):
                    # prevent SIGINT (ctrl+c) from exiting
                    # the whole program
                    pass

                signal.signal(signal.SIGINT, sigint_handler)
                args = shlex.split(cmd)
                os.execvp(args[0], args)

            else:
                # this is the parent process fork.
                # store child fd and pid
                self.stdin = fd
                self.stdout = fd
                self.pid = child_pid
        else:
            (master, slave) = pty.openpty()
            self.stdin = master
            self.stdout = master
            self.name = os.ttyname(slave)
            self.set_echo(echo)

    def set_echo(self, echo_on: bool) -> None:
        (iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(self.stdin)
        if echo_on:
            lflag = lflag & termios.ECHO  # type: ignore
        else:
            lflag = lflag & ~termios.ECHO  # type: ignore
        termios.tcsetattr(
            self.stdin,
            termios.TCSANOW,
            [iflag, oflag, cflag, lflag, ispeed, ospeed, cc],
        )

    def set_winsize(self, rows: int, cols: int):
        xpix = 0
        ypix = 0
        winsize = struct.pack("HHHH", rows, cols, xpix, ypix)
        if self.stdin is None:
            raise RuntimeError("fd stdin not assigned")
        fcntl.ioctl(self.stdin, termios.TIOCSWINSZ, winsize)

    def read(self) -> Optional[str]:
        if self.stdout is None:
            return "done"
        timeout_sec = 0
        (data_to_read, _, _) = select.select([self.stdout], [], [], timeout_sec)
        if data_to_read:
            try:
                response = os.read(self.stdout, self.max_read_bytes).decode()
            except (OSError, UnicodeDecodeError):
                return None
            return response
        return None

    def write(self, data: str):
        edata = data.encode()
        os.write(self.stdin, edata)


================================================
FILE: gdbgui/server/server.py
================================================
import os
import socket
import webbrowser

from .constants import DEFAULT_HOST, DEFAULT_PORT, colorize

try:
    from gdbgui.SSLify import SSLify, get_ssl_context  # noqa
except ImportError:
    print("Warning: Optional SSL support is not available")

    def get_ssl_context(private_key, certificate):  # noqa
        return None


def get_extra_files():
    """returns a list of files that should be watched by the Flask server
    when in debug mode to trigger a reload of the server
    """
    FILES_TO_SKIP = ["src/gdbgui.js"]
    THIS_DIR = os.path.dirname(os.path.abspath(__file__))
    extra_dirs = [THIS_DIR]
    extra_files = []
    for extra_dir in extra_dirs:
        for dirname, _, files in os.walk(extra_dir):
            for filename in files:
                filepath = os.path.join(dirname, filename)
                if os.path.isfile(filepath) and filepath not in extra_files:
                    for skipfile in FILES_TO_SKIP:
                        if skipfile not in filepath:
                            extra_files.append(filepath)
    return extra_files


def run_server(
    *,
    app=None,
    socketio=None,
    host=DEFAULT_HOST,
    port=DEFAULT_PORT,
    debug=False,
    open_browser=True,
    browsername=None,
    testing=False,
    private_key=None,
    certificate=None,
):
    """Run the server of the gdb gui"""

    kwargs = {}
    ssl_context = get_ssl_context(private_key, certificate)
    if ssl_context:
        # got valid ssl context
        # force everything through https
        SSLify(app)
        # pass ssl_context to flask
        kwargs["ssl_context"] = ssl_context

    url = "%s:%s" % (host, port)
    if kwargs.get("ssl_context"):
        protocol = "https://"
        url_with_prefix = "https://" + url
    else:
        protocol = "http://"
        url_with_prefix = "http://" + url

    socketio.server_options["allow_upgrades"] = False
    socketio.init_app(app)

    if testing is False:
        if host == DEFAULT_HOST:
            url = (DEFAULT_HOST, port)
        else:
            try:
                url = (socket.gethostbyname(socket.gethostname()), port)
            except Exception:
                url = (host, port)

        if open_browser is True and debug is False:
            browsertext = repr(browsername) if browsername else "default browser"
            args = (browsertext,) + url
            text = ("Opening gdbgui with %s at " + protocol + "%s:%d") % args
            print(colorize(text))
            b = webbrowser.get(browsername) if browsername else webbrowser
            b.open(url_with_prefix)
        else:
            print(colorize(f"View gdbgui at {protocol}{url[0]}:{url[1]}"))
        print(
            colorize(f"View gdbgui dashboard at {protocol}{url[0]}:{url[1]}/dashboard")
        )

        print("exit gdbgui by pressing CTRL+C")
        try:
            socketio.run(
                app,
                debug=debug,
                port=int(port),
                host=host,
                extra_files=get_extra_files(),
                **kwargs,
            )
        except KeyboardInterrupt:
            # Process was interrupted by ctrl+c on keyboard, show message
            pass


================================================
FILE: gdbgui/server/sessionmanager.py
================================================
import datetime
import logging
import os
import signal
import traceback
from collections import defaultdict
from typing import Dict, List, Optional, Set

from pygdbmi.IoManager import IoManager

from .ptylib import Pty

logger = logging.getLogger(__name__)


class DebugSession:
    def __init__(
        self,
        *,
        pygdbmi_controller: IoManager,
        pty_for_gdbgui: Pty,
        pty_for_gdb: Pty,
        pty_for_debugged_program: Pty,
        command: str,
        mi_version: str,
        pid: int,
    ):
        self.command = command
        self.pygdbmi_controller = pygdbmi_controller
        self.pty_for_gdbgui = pty_for_gdbgui
        self.pty_for_gdb = pty_for_gdb
        self.pty_for_debugged_program = pty_for_debugged_program
        self.mi_version = mi_version
        self.pid = pid
        self.start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.client_ids: Set[str] = set()

    def terminate(self):
        if self.pid:
            try:
                os.kill(self.pid, signal.SIGKILL)
            except Exception as e:
                logger.error(f"Failed to kill pid {self.pid}: {str(e)}")

        self.pygdbmi_controller = None

    def to_dict(self):
        return {
            "pid": self.pid,
            "start_time": self.start_time,
            "command": self.command,
            "c2": "hi",
            "client_ids": list(self.client_ids),
        }

    def add_client(self, client_id: str):
        self.client_ids.add(client_id)

    def remove_client(self, client_id: str):
        self.client_ids.discard(client_id)
        if len(self.client_ids) == 0:
            self.terminate()


class SessionManager(object):
    def __init__(self):
        self.debug_session_to_client_ids: Dict[DebugSession, List[str]] = defaultdict(
            list
        )  # key is controller, val is list of client ids

        self.gdb_reader_thread = None

    def connect_client_to_debug_session(
        self, *, desired_gdbpid: int, client_id: str
    ) -> DebugSession:
        debug_session = self.debug_session_from_pid(desired_gdbpid)

        if not debug_session:
            raise ValueError(f"No existing gdb process with pid {desired_gdbpid}")
        debug_session.add_client(client_id)
        self.debug_session_to_client_ids[debug_session].append(client_id)
        return debug_session

    def add_new_debug_session(
        self, *, gdb_command: str, mi_version: str, client_id: str
    ) -> DebugSession:
        pty_for_debugged_program = Pty()
        pty_for_gdbgui = Pty(echo=False)
        gdbgui_startup_cmds = [
            f"new-ui {mi_version} {pty_for_gdbgui.name}",
            f"set inferior-tty {pty_for_debugged_program.name}",
            "set pagination off",
        ]
        # instead of writing to the pty after it starts, add startup
        # commands to gdb. This allows gdb to be run as sudo and prompt for a
        # password, for example.
        gdbgui_startup_cmds_str = " ".join([f"-iex='{c}'" for c in gdbgui_startup_cmds])
        pty_for_gdb = Pty(cmd=f"{gdb_command} {gdbgui_startup_cmds_str}")

        pid = pty_for_gdb.pid
        debug_session = DebugSession(
            pygdbmi_controller=IoManager(
                os.fdopen(pty_for_gdbgui.stdin, mode="wb", buffering=0),  # type: ignore
                os.fdopen(pty_for_gdbgui.stdout, mode="rb", buffering=0),  # type: ignore
                None,
            ),
            pty_for_gdbgui=pty_for_gdbgui,
            pty_for_gdb=pty_for_gdb,
            pty_for_debugged_program=pty_for_debugged_program,
            command=gdb_command,
            mi_version=mi_version,
            pid=pid,
        )
        debug_session.add_client(client_id)
        self.debug_session_to_client_ids[debug_session] = [client_id]
        return debug_session

    def remove_debug_session_by_pid(self, gdbpid: int) -> List[str]:
        debug_session = self.debug_session_from_pid(gdbpid)
        if debug_session:
            orphaned_client_ids = self.remove_debug_session(debug_session)
        else:
            logger.info(f"could not find debug session with gdb pid {gdbpid}")
            orphaned_client_ids = []
        return orphaned_client_ids

    def remove_debug_session(self, debug_session: DebugSession) -> List[str]:
        logger.info(f"Removing debug session for pid {debug_session.pid}")
        try:
            debug_session.terminate()
        except Exception:
            logger.error(traceback.format_exc())
        orphaned_client_ids = self.debug_session_to_client_ids.pop(debug_session, [])
        return orphaned_client_ids

    def remove_debug_sessions_with_no_clients(self) -> None:
        to_remove = []
        for debug_session, _ in self.debug_session_to_client_ids.items():
            if len(debug_session.client_ids) == 0:
                to_remove.append(debug_session)
        for debug_session in to_remove:
            self.remove_debug_session(debug_session)

    def get_pid_from_debug_session(self, debug_session: DebugSession) -> Optional[int]:
        if debug_session and debug_session.pid:
            return debug_session.pid
        return None

    def debug_session_from_pid(self, pid: int) -> Optional[DebugSession]:
        for debug_session in self.debug_session_to_client_ids:
            this_pid = self.get_pid_from_debug_session(debug_session)
            if this_pid == pid:
                return debug_session
        return None

    def debug_session_from_client_id(self, client_id: str) -> Optional[DebugSession]:
        for debug_session, client_ids in self.debug_session_to_client_ids.items():
            if client_id in client_ids:
                return debug_session
        return None

    def get_dashboard_data(self) -> List[DebugSession]:
        return [
            debug_session.to_dict()
            for debug_session in self.debug_session_to_client_ids.keys()
        ]

    def disconnect_client(self, client_id: str):
        for debug_session, client_ids in self.debug_session_to_client_ids.items():
            if client_id in client_ids:
                client_ids.remove(client_id)
                debug_session.remove_client(client_id)
        self.remove_debug_sessions_with_no_clients()


================================================
FILE: gdbgui/src/js/Actions.ts
================================================
import { store } from "statorgfc";
import GdbApi from "./GdbApi";
import SourceCode from "./SourceCode";
import Locals from "./Locals";
import Memory from "./Memory";
import constants from "./constants";
import React from "react";
void React; // using jsx implicity uses React

const Actions = {
  clear_program_state: function() {
    store.set("line_of_source_to_flash", undefined);
    store.set("paused_on_frame", undefined);
    store.set("selected_frame_num", 0);
    store.set("current_thread_id", undefined);
    store.set("stack", []);
    store.set("threads", []);
    Memory.clear_cache();
    Locals.clear();
  },
  inferior_program_starting: function() {
    store.set("inferior_program", constants.inferior_states.running);
    Actions.clear_program_state();
  },
  inferior_program_resuming: function() {
    store.set("inferior_program", constants.inferior_states.running);
  },
  inferior_program_paused: function(frame = {}) {
    store.set("inferior_program", constants.inferior_states.paused);
    store.set(
      "source_code_selection_state",
      constants.source_code_selection_states.PAUSED_FRAME
    );
    store.set("paused_on_frame", frame);
    // @ts-expect-error ts-migrate(2339) FIXME: Property 'fullname' does not exist on type '{}'.
    store.set("fullname_to_render", frame.fullname);
    // @ts-expect-error ts-migrate(2339) FIXME: Property 'line' does not exist on type '{}'.
    store.set("line_of_source_to_flash", parseInt(frame.line));
    // @ts-expect-error ts-migrate(2339) FIXME: Property 'addr' does not exist on type '{}'.
    store.set("current_assembly_address", frame.addr);
    store.set("source_code_infinite_scrolling", false);
    SourceCode.make_current_line_visible();
    Actions.refresh_state_for_gdb_pause();
  },
  inferior_program_exited: function() {
    store.set("inferior_program", constants.inferior_states.exited);
    store.set("disassembly_for_missing_file", []);
    store.set("root_gdb_tree_var", null);
    store.set("previous_register_values", {});
    store.set("current_register_values", {});
    store.set("inferior_pid", null);
    Actions.clear_program_state();
  },
  /**
   * Request relevant store information from gdb to refresh UI
   */
  refresh_state_for_gdb_pause: function() {
    GdbApi.run_gdb_command(GdbApi._get_refresh_state_for_pause_cmds());
  },
  execute_console_command: function(command: any) {
    if (store.get("refresh_state_after_sending_console_command")) {
      GdbApi.run_command_and_refresh_state(command);
    } else {
      GdbApi.run_gdb_command(command);
    }
  },
  onConsoleCommandRun: function() {
    if (store.get("refresh_state_after_sending_console_command")) {
      GdbApi.run_gdb_command(GdbApi._get_refresh_state_for_pause_cmds());
    }
  },
  clear_console: function() {
    store.set("gdb_console_entries", []);
  },
  add_console_entries: function(entries: any, type: any) {
    if (type === constants.console_entry_type.STD_OUT) {
      // ignore
      return;
    }
    if (!Array.isArray(entries)) {
      entries = [entries];
    }

    const pty = store.get("gdbguiPty");
    if (pty) {
      entries.forEach((data: string) => {
        const entriesToIgnore = [
          // No registers. appears when refresh commands are run when program hasn't started.
          // TODO The real fix for this is to not refresh commands when the program is not running.
          "No registers."
        ];
        if (entriesToIgnore.indexOf(data) > -1) {
          return;
        }
        // @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTypeMap' does not exist on type 'Re... Remove this comment to see the full error message
        pty.write(constants.colorTypeMap[type] ?? constants.xtermColors["reset"]);
        pty.writeln(data);
        pty.write(constants.xtermColors["reset"]);
      });
    } else {
      console.error("Pty not available. New entries are:", entries);
    }
  },
  add_gdb_response_to_console(mi_obj: any) {
    if (!mi_obj) {
      return;
    }
    // Update status
    let entries = [],
      error = false;
    if (mi_obj.message) {
      if (mi_obj.message === "error") {
        error = true;
      } else {
        entries.push(mi_obj.message);
      }
    }
    if (mi_obj.payload) {
      const interesting_keys = ["msg", "reason", "signal-name", "signal-meaning"];
      for (let k of interesting_keys) {
        if (mi_obj.payload[k]) {
          entries.push(mi_obj.payload[k]);
        }
      }

      if (mi_obj.payload.frame) {
        for (let i of ["file", "func", "line", "addr"]) {
          if (i in mi_obj.payload.frame) {
            entries.push(`${i}: ${mi_obj.payload.frame[i]}`);
          }
        }
      }
    }
    let type = error
      ? constants.console_entry_type.STD_ERR
      : constants.console_entry_type.STD_OUT;
    Actions.add_console_entries(entries, type);
  },
  toggle_modal_visibility() {
    store.set("show_modal", !store.get("show_modal"));
  },
  show_modal(header: any, body: any) {
    store.set("modal_header", header);
    store.set("modal_body", body);
    store.set("show_modal", true);
  },
  set_gdb_binary_and_arguments(binary: any, args: any) {
    // remove list of source files associated with the loaded binary since we're loading a new one
    store.set("source_file_paths", []);
    store.set("language", "c_family");
    store.set("inferior_binary_path", null);
    Actions.inferior_program_exited();
    let cmds = GdbApi.get_load_binary_and_arguments_cmds(binary, args);
    GdbApi.run_gdb_command(cmds);
    GdbApi.get_inferior_binary_last_modified_unix_sec(binary);
  },
  connect_to_gdbserver(user_input: any) {
    // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
    store.set("source_file_paths", []);
    store.set("language", "c_family");
    store.set("inferior_binary_path", null);
    Actions.inferior_program_exited();
    GdbApi.run_gdb_command([`-target-select remote ${user_input}`]);
  },
  remote_connected() {
    Actions.inferior_program_paused();
    let cmds = [];
    if (store.get("auto_add_breakpoint_to_main")) {
      Actions.add_console_entries(
        "Connected to remote target! Adding breakpoint to main, then continuing target execution.",
        constants.console_entry_type.GDBGUI_OUTPUT
      );
      cmds.push("-break-insert main");
      cmds.push("-exec-continue");
      cmds.push(GdbApi.get_break_list_cmd());
    } else {
      Actions.add_console_entries(
        'Connected to remote target! Add breakpoint(s), then press "continue" button (do not press "run").',
        constants.console_entry_type.GDBGUI_OUTPUT
      );
    }
    GdbApi.run_gdb_command(cmds);
  },
  attach_to_process(user_input: any) {
    // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
    GdbApi.run_gdb_command(`-target-attach ${user_input}`);
  },
  fetch_source_files() {
    store.set("source_file_paths", []);
    GdbApi.run_gdb_command("-file-list-exec-source-files");
  },
  view_file(fullname: any, line: any) {
    store.set("fullname_to_render", fullname);
    store.set("source_code_infinite_scrolling", false);
    Actions.set_line_state(line);
  },
  set_line_state(line: any) {
    store.set("source_code_infinite_scrolling", false);
    store.set(
      "source_code_selection_state",
      constants.source_code_selection_states.USER_SELECTION
    );
    store.set("line_of_source_to_flash", parseInt(line));
    store.set("make_current_line_visible", true);
  },
  clear_cached_assembly() {
    store.set("disassembly_for_missing_file", []);
    let cached_source_files = store.get("cached_source_files");
    for (let file of cached_source_files) {
      file.assembly = {};
    }
    store.set("cached_source_files", cached_source_files);
  },
  update_max_lines_of_code_to_fetch(new_value: any) {
    if (new_value <= 0) {
      new_value = constants.default_max_lines_of_code_to_fetch;
    }
    store.set("max_lines_of_code_to_fetch", new_value);
    localStorage.setItem("max_lines_of_code_to_fetch", JSON.stringify(new_value));
  },
  send_signal(signal_name: any, pid: any) {
    $.ajax({
      beforeSend: function(xhr) {
        xhr.setRequestHeader(
          "x-csrftoken",
          // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.
          initial_data.csrf_token
        ); /* global initial_data */
      },
      url: "/send_signal_to_pid",
      cache: false,
      type: "POST",
      data: { signal_name: signal_name, pid: pid },
      success: function(response) {
        Actions.add_console_entries(
          response.message,
          constants.console_entry_type.GDBGUI_OUTPUT
        );
      },
      error: function(response) {
        if (response.responseJSON && response.responseJSON.message) {
          Actions.add_console_entries(
            // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.
            _.escape(response.responseJSON.message),
            constants.console_entry_type.STD_ERR
          );
        } else {
          Actions.add_console_entries(
            `${response.statusText} (${response.status} error)`,
            constants.console_entry_type.STD_ERR
          );
        }
        console.error(response);
      },
      complete: function() {}
    });
  }
};

export default Actions;


================================================
FILE: gdbgui/src/js/BinaryLoader.tsx
================================================
import React from "react";
import constants from "./constants";
import Actions from "./Actions";
import Util from "./Util";
import ToolTipTourguide from "./ToolTipTourguide";

const TARGET_TYPES = {
  file: "file",
  server: "server",
  process: "process",
  target_download: "target_download"
};

type State = any;

/**
 * The BinaryLoader component allows the user to select their binary
 * and specify inputs
 */
class BinaryLoader extends React.Component<{}, State> {
  constructor(props: {}) {
    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.
    super();

    this.state = {
      past_binaries: [],
      // @ts-expect-error ts-migrate(2339) FIXME: Property 'initial_user_input' does not exist on ty... Remove this comment to see the full error message
      user_input: props.initial_user_input.join(" "),
      // @ts-expect-error ts-migrate(2339) FIXME: Property 'initial_user_input' does not exist on ty... Remove this comment to see the full error message
      initial_set_target_app: props.initial_user_input.length, // if user supplied initial binary, load it immediately
      target_type: TARGET_TYPES.file
    };
    try {
      // @ts-expect-error ts-migrate(2542) FIXME: Index signature in type 'Readonly<any>' only permi... Remove this comment to see the full error message
      this.state.past_binaries = _.uniq(
        // @ts-expect-error ts-migrate(2345) FIXME: Type 'null' is not assignable to type 'string'.
        JSON.parse(localStorage.getItem("past_binaries"))
      );
      if (!this.state.user_input) {
        let most_recent_binary = this.state.past_binaries[0];
        // @ts-expect-error ts-migrate(2542) FIXME: Index signature in type 'Readonly<any>' only permi... Remove this comment to see the full error message
        this.state.user_input = most_recent_binary;
      }
    } catch (err) {
      // @ts-expect-error ts-migrate(2542) FIXME: Index signature in type 'Readonly<any>' only permi... Remove this comment to see the full error message
      this.state.past_binaries = [];
    }
  }
  render() {
    let button_text, title, placeholder;

    if (this.state.target_type === TARGET_TYPES.file) {
      button_text = "Load Binary";
      title =
        "Loads the binary and any arguments present in the input to the right. Backslashes are treated as escape characters. Windows users can either use two backslashes in paths, or forward slashes.";
      placeholder = "/path/to/target/executable -and -flags";
    } else if (this.state.target_type === TARGET_TYPES.server) {
      // https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Target-Manipulation.html#GDB_002fMI-Target-Manipulation
      // -target-select
      button_text = "Connect to gdbserver";
      title = "Connect GDB to the remote target.";
      placeholder = "examples: 127.0.0.1:9999 | /dev/ttya";
    } else if (this.state.target_type === TARGET_TYPES.process) {
      // -target-attach
      button_text = "Attach to Process";
      title =
        "Attach to a process pid or a file file outside of GDB, or a thread group gid. If attaching to a thread group, the id previously returned by ‘-list-thread-groups --available’ must be used. Note: to do this, you usually need to run gdbgui as sudo.";
      placeholder = "pid | gid | file";
    }

    return (
      <form style={{ marginBottom: 1, flex: "2 0 0" }}>
        <div className="input-group input-group-sm">
          <div className="dropdown input-group-btn">
            <button
              className="btn btn-primary dropdown-toggle"
              type="button"
              data-toggle="dropdown"
            >
              <span className="caret" />
            </button>

            <ul className="dropdown-menu">
              <li>
                <a
                  className="pointer"
                  onClick={() => this.setState({ target_type: TARGET_TYPES.file })}
                >
                  Load Binary
                </a>
              </li>
              <li>
                <a
                  className="pointer"
                  onClick={() => this.setState({ target_type: TARGET_TYPES.server })}
                >
                  Connect to gdbserver
                </a>
              </li>
              <li>
                <a
                  className="pointer"
                  onClick={() => this.setState({ target_type: TARGET_TYPES.process })}
                >
                  Attach to Process
                </a>
              </li>
            </ul>

            <button
              type="button"
              title={title}
              onClick={this.click_set_target_app.bind(this)}
              className="btn btn-primary"
            >
              {button_text}
            </button>
          </div>

          <input
            type="text"
            placeholder={placeholder}
            list="past_binaries"
            style={{ fontFamily: "courier" }}
            className="form-control"
            onKeyUp={this.onkeyup_user_input.bind(this)}
            onChange={this.onchange_user_inpu.bind(this)}
            value={this.state.user_input}
          />
        </div>
        <ToolTipTourguide
          // @ts-expect-error ts-migrate(2322) FIXME: Property 'step_num' does not exist on type 'Intrin... Remove this comment to see the full error message
          step_num={1}
          position={"bottomcenter"}
          content={
            <div>
              <h5>Enter the path to the binary you wish to debug here.</h5>
              <p>This is the first thing you should do.</p>
              <p>
                The path can be absolute, or relative to where gdbgui was launched from.
              </p>
            </div>
          }
        />
        <ToolTipTourguide
          // @ts-expect-error ts-migrate(2322) FIXME: Property 'step_num' does not exist on type 'Intrin... Remove this comment to see the full error message
          step_num={2}
          position={"bottomleft"}
          content={
            <div>
              <h5>Press this button to load the executable specified in the input.</h5>
              <p>This is the second thing you should do.</p>

              <p>
                Debugging won't start, but you will be able to set breakpoints. If
                present,{" "}
                <a href="https://en.wikipedia.org/wiki/Debug_symbol">debugging symbols</a>{" "}
                in the binary are also loaded.
              </p>
              <p>
                If you don't want to debug a binary, click the dropdown to choose a
                different target type.
              </p>
            </div>
          }
        />
        <datalist id="past_binaries">
          {this.state.past_binaries.map((b: any, i: any) => (
            <option key={i}>{b}</option>
          ))}
        </datalist>
      </form>
    );
  }
  componentDidMount() {
    if (this.state.initial_set_target_app) {
      this.setState({ initial_set_target_app: false });
      this.set_target_app();
    }
  }
  onkeyup_user_input(e: any) {
    if (e.keyCode === constants.ENTER_BUTTON_NUM) {
      this.set_target_app();
    }
  }
  onchange_user_inpu(e: any) {
    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'initial_data'.
    if (initial_data.using_windows) {
      // replace backslashes with forward slashes when using windows
      this.setState({ user_input: e.target.value.replace(/\\/g, "/") });
    } else {
      this.setState({ user_input: e.target.value });
    }
  }
  click_set_target_app() {
    this.set_target_app();
  }
  // save to list of binaries used that autopopulates the input dropdown
  _add_user_input_to_history(binary_and_args: any) {
    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.
    _.remove(this.state.past_binaries, (i: any) => i === binary_and_args);
    this.state.past_binaries.unshift(binary_and_args); // add to beginning
    this.setState({ past_binaries: this.state.past_binaries });
    // @ts-expect-error ts-migrate(2345) FIXME: Type 'never[]' is not assignable to type 'string'.
    localStorage.setItem("past_binaries", JSON.stringify(this.state.past_binaries) || []);

    // @ts-expect-error ts-migrate(2345) FIXME: Type 'null' is not assignable to type 'string'.
    let num_gdbgui_sessions = parseInt(localStorage.getItem("num_gdbgui_sessions"));
    if (isNaN(num_gdbgui_sessions)) {
      num_gdbgui_sessions = 0;
    }
  }
  /**
   * parse tokens with awareness of double quotes
   *
   * @param      {string}  user_input raw input from user
   * @return     {Object}  { the binary (string) and arguments (array) parsed from user input }
   */
  _parse_binary_and_args_from_user_input(user_input: any) {
    let list_of_params = Util.string_to_array_safe_quotes(user_input),
      binary = "",
      args: any = [],
      len = list_of_params.length;
    if (len === 1) {
      binary = list_of_params[0];
    } else if (len > 1) {
      binary = list_of_params[0];
      args = list_of_params.slice(1, len);
    }
    return { binary: binary, args: args.join(" ") };
  }
  set_target_app() {
    let user_input = this.state.user_input.trim();

    if (user_input === "") {
      Actions.add_console_entries(
        "input cannot be empty",
        constants.console_entry_type.GDBGUI_OUTPUT
      );
      return;
    }

    this._add_user_input_to_history(user_input);

    if (this.state.target_type === TARGET_TYPES.file) {
      const { binary, args } = this._parse_binary_and_args_from_user_input(user_input);
      Actions.set_gdb_binary_and_arguments(binary, args);
    } else if (this.state.target_type === TARGET_TYPES.server) {
      Actions.connect_to_gdbserver(user_input);
    } else if (this.state.target_type === TARGET_TYPES.process) {
      Actions.attach_to_process(user_input);
    }
  }
}

export default BinaryLoader;


================================================
FILE: gdbgui/src/js/Breakpoints.tsx
================================================
import React from "react";
import { store } from "statorgfc";
import GdbApi from "./GdbApi";
import Actions from "./Actions";
import Util from "./Util";
import FileOps from "./FileOps";
import { FileLink } from "./Links";
import constants from "./constants";

const BreakpointSourceLineCache = {
  _cache: {},
  get_line: function(fullname: any, linenum: any) {
    if (
      // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.
      BreakpointSourceLineCache._cache["fullname"] !== undefined &&
      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.
      _.isString(BreakpointSourceLineCache._cache["fullname"][linenum])
    ) {
      // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.
      return BreakpointSourceLineCache._cache["fullname"][linenum];
    }
    return null;
  },
  add_line: function(fullname: any, linenum: any, escaped_text: any) {
    // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.
    if (!_.isObject(BreakpointSourceLineCache._cache["fullname"])) {
      // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.
      BreakpointSourceLineCache._cache["fullname"] = {};
    }
    // @ts-expect-error ts-migrate(7053) FIXME: Property 'fullname' does not exist on type '{}'.
    BreakpointSourceLineCache._cache["fullname"][linenum] = escaped_text;
  }
};

type BreakpointState = any;

class Breakpoint extends React.Component<{}, BreakpointState> {
  constructor(props: {}) {
    super(props);
    this.state = {
      breakpoint_condition: "",
      editing_breakpoint_condition: false
    };
  }
  get_source_line(fullname: any, linenum: any) {
    // if we have the source file cached, we can display the line of text
    const MAX_CHARS_TO_SHOW_FROM_SOURCE = 40;
    let line = null;
    if (BreakpointSourceLineCache.get_line(fullname, linenum)) {
      line = BreakpointSourceLineCache.get_line(fullname, linenum);
      // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2.
    } else if (FileOps.line_is_cached(fullname, linenum)) {
      let syntax_highlighted_line = FileOps.get_line_from_file(fullname, linenum);
      // @ts-expect-error ts-migrate(2304) FIXME: Cannot find name '_'.
      line = _.trim(Util.get_text_from_html(syntax_highlighted_line));

      if (line.length > MAX_CHARS_TO_SHOW_FROM_SOURCE) {
        line = line.slice(0, MAX_CHARS_TO_SHOW_FROM_SOURCE) + "...";
      }
      BreakpointSourceLineCache.add_line(fullname, linenum, line);
    }

    if (line) {
      return (
        <span className="monospace" style={{ whiteSpace: "nowrap", fontSize: "0.9em" }}>
          {line || <br />}
        </span>
      );
    }
    return "(file not cached)";
  }
  get_delete_jsx(bkpt_num_to_delete: any) {
    return (
      <div
        style={{ width: "10px", display: "inline" }}
        className="pointer breakpoint_trashcan"
        onClick={e => {
          e.stopPropagation();
          Breakpoints.delete_breakpoint(bkpt_num_to_delete);
        }}
        title={`Delete breakpoint ${bkpt_num_to_delete}`}
      >
        <span className="glyphicon glyphicon-trash"> </span>
      </div>
    );
  }
  get_num_times_hit(bkpt: any) {
    if (
      bkpt.times === undefined || // E.g. 'bkpt' is a child breakpoint
      bkpt.times == 0
    ) {
      return "";
    } else if (bkpt.times == 1) {
      return "1 hit";
    } else {
      return `${bkpt.times} hits`;
    }
  }
  on_change_bkpt_cond(e: any) {
    this.setState({
      breakpoint_condition: e.target.value,
      editing_breakpoint_condition: true
    });
  }
  on_key_up_bktp_cond(number: any, e: any) {
    if (e.keyCode === constants.ENTER_BUTTON_NUM) {
      this.setState({ editing_breakpoint_condition: false });
      Breakpoints.set_breakpoint_condition(e.target.value, number);
    }
  }
  on_break_cond_click(e: any) {
    this.setState({
      editing_breakpoint_condition: true
    });
  }
  render() {
    // @ts-expect-error ts-migrate(2339) FIXME: Property 'bkpt' does not exist on type 'Readonly<{... Remove this comment to see the full error message
    let b = this.props.bkpt,
      checked = b.enabled === "y" ? "checked" : "",
      source_line = this.get_source_line(b.fullname_to_display, b.line);

    let info_glyph, function_jsx, bkpt_num_to_delete;
    if (b.is_child_breakpoint) {
      bkpt_num_to_delete = b.parent_breakpoint_number;
      info_glyph = (
        <span
          className="glyphicon glyphicon-th-list"
          title="Child breakpoint automatically created from parent. If parent or any child of this tree is deleted, all related breakpoints will be deleted."
        />
      );
    } else if (b.is_parent_breakpoint) {
      info_glyph = (
        <span
          className="glyphicon glyphicon-th-list"
          title="Parent breakpoint with one or more child breakpoints. If parent or any child of this tree is deleted, all related breakpoints will be deleted."
        />
      );
      bkpt_num_to_delete = b.number;
    } else {
      bkpt_num_to_delete = b.number;
      info_glyph = "";
    }

    const delete_jsx = this.get_delete_jsx(bkpt_num_to_delete);
    let location_jsx = (
      <FileLink
        fullname={b.fullname_to_display}
        file={b.fullname_to_display}
        line={b.line}
      />
    );

    if (b.is_parent_breakpoint) {
      function_jsx = (
        <span className="placeholder">
          {info_glyph} parent breakpoint on inline, template, or ambiguous location
        </span>
      );
    } else {
      let func = b.func === undefined ? "(unknown function)" : b.func;
      let break_condition = (
        <div
          onClick={this.on_break_cond_click.bind(this)}
          className="inline"
          title={`${
            this.state.breakpoint_condition ? "Modify or remove" : "Add"
          } breakpoint condition`}
        >
          <span className="glyphicon glyphicon-edit"></span>
          <span className={`italic ${this.state.breakpoint_condition ? "bold" : ""}`}>
            condition
          </span>
        </div>
      );
      if (this.state.editing_breakpoint_condition) {
        break_condition = (
          <input
            type="text"
            style={{
              display: "inline",
              width: "110px",
              padding: "10px 10px",
              height: "25px",
              fontSize: "1em"
            }}
            placeholder="Break condition"
            className="form-control"
            onKeyUp={this.on_key_up_bktp_cond.bind(this, b.number)}
            onChange={this.on_change_bkpt_cond.bind(this)}
            value={this.state.breakpoint_condition}
          />
        );
      }

      const times_hit = this.get_num_times_hit(b);
      function_jsx = (
        <div style={{ display: "inline" }}>
          <span className="monospace" style={{ paddingRight: "5px" }}>
            {info_glyph} {func}
          </span>
          <span
            style={{
              color: "#bbbbbb",
              fontStyle: "italic",
              paddingRight: "5px"
            }}
          >
            thread groups: {b["thread-groups"]}
          </span>
          <span>{break_condition}</span>
          <span
            style={{
              color: "#bbbbbb",
              fontStyle: "italic",
              paddingLeft: "5px"
            }}
          >
            {times_hit}
          </span>
        </div>
      );
    }

    return (
      <div
        className="breakpoint"
        onClick={() => Actions.view_file(b.fullname_to_display, b.line)}
      >
        <table
          style={{
            width: "100%",
            fontSize: "0.9em",
            borderWidth: "0px"
          }}
          className="lighttext table-condensed"
        >
          <tbody>
            <tr>
              <td>
                <input
                  type="checkbox"
                  // @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'boolean |... Remove this comment to see the full error message
                  checked={checked}
                  onChange={() => Breakpoints.enable_or_disable_bkpt(checked, b.number)}
                />
                {function_jsx} {delete_jsx}
              </td>
            </tr>

            <tr>
              <td>{location_jsx}</td>
            </tr>

            <tr>
              <td>{source_line}</td>
            </tr>
          </tbody>
        </table>
      </div>
    );
  } // render function
}

class Breakpoints extends React.Component {
  constructor() {
    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.
    super();
    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message
    store.connectComponentState(this, ["breakpoints"]);
  }
  render() {
    let breakpoints_jsx = [];
    for (let b of store.get("breakpoints")) {
      // @ts-expect-error ts-migrate(2322) FIXME: Property 'bkpt' does not exist on type 'IntrinsicA... Remove this comment to see the full error message
      breakpoints_jsx.push(<Breakpoint bkpt={b} key={b.number} />);
    }

    if (breakpoints_jsx.length) {
      return breakpoints_jsx;
    } else {
      return <span className="placeholder">no breakpoints</span>;
    }
  }
  static enable_or_disable_bkpt(checked: any, bkpt_num: any) {
    if (checked) {
      GdbApi.run_gdb_command([`-break-disable ${bkpt_num}`, GdbApi.get_break_list_cmd()]);
    } else {
      GdbApi.run_gdb_command([`-break-enable ${bkpt_num}`, GdbApi.get_break_list_cmd()]);
    }
  }
  static set_breakpoint_condition(condition: any, bkpt_num: any) {
    GdbApi.run_gdb_command([
      `-break-condition ${bkpt_num} ${condition}`,
      GdbApi.get_break_list_cmd()
    ]);
  }
  static remove_breakpoint_if_present(fullname: any, line: any) {
    if (Breakpoints.has_breakpoint(fullname, line)) {
      let number = Breakpoints.get_breakpoint_number(fullname, line);
      let cmd = [GdbApi.get_delete_break_cmd(number), GdbApi.get_break_list_cmd()];
      GdbApi.run_gdb_command(cmd);
    }
  }
  static add_or_remove_breakpoint(fullname: any, line: any) {
    if (Breakpoints.has_breakpoint(fullname, line)) {
      Breakpoints.remove_breakpoint_if_present(fullname, line);
    } else {
      Breakpoints.add_breakpoint(fullname, line);
    }
  }
  static add_breakpoint(fullname: any, line: any) {
    GdbApi.run_gdb_command(GdbApi.get_insert_break_cmd(fullname, line));
  }
  static has_breakpoint(fullname: any, line: any) {
    let bkpts = store.get("breakpoints");
    for (let b of bkpts) {
      if (b.fullname === fullname && b.line == line) {
        return true;
      }
    }
    return false;
  }
  static get_breakpoint_number(fullname: any, line: any) {
    let bkpts = store.get("breakpoints");
    for (let b of bkpts) {
      if (b.fullname === fullname && b.line == line) {
        return b.number;
      }
    }
    console.error(`could not find breakpoint for ${fullname}:${line}`);
  }
  static delete_breakpoint(breakpoint_number: any) {
    GdbApi.run_gdb_command([
      GdbApi.get_delete_break_cmd(breakpoint_number),
      GdbApi.get_break_list_cmd()
    ]);
  }
  static get_breakpoint_lines_for_file(fullname: any) {
    return store
      .get("breakpoints")
      .filter((b: any) => b.fullname_to_display === fullname && b.enabled === "y")
      .map((b: any) => parseInt(b.line));
  }
  static get_disabled_breakpoint_lines_for_file(fullname: any) {
    return store
      .get("breakpoints")
      .filter((b: any) => b.fullname_to_display === fullname && b.enabled !== "y")
      .map((b: any) => parseInt(b.line));
  }
  static get_conditional_breakpoint_lines_for_file(fullname: any) {
    return store
      .get("breakpoints")
      .filter((b: any) => b.fullname_to_display === fullname && b.cond !== undefined)
      .map((b: any) => parseInt(b.line));
  }
  static save_breakpoints(payload: any) {
    store.set("breakpoints", []);
    if (payload && payload.BreakpointTable && payload.BreakpointTable.body) {
      for (let breakpoint of payload.BreakpointTable.body) {
        Breakpoints.save_breakpoint(breakpoint);
      }
    }
  }
  static save_breakpoint(breakpoint: any) {
    let bkpt = Object.assign({}, breakpoint);

    bkpt.is_parent_breakpoint = bkpt.addr === "(MULTIPLE)";

    // parent breakpoints have numbers like "5.6", whereas normal breakpoints and parent breakpoints have numbers like "5"
    bkpt.is_child_breakpoint = parseInt(bkpt.number) !== parseFloat(bkpt.number);
    bkpt.is_normal_breakpoint = !bkpt.is_parent_breakpoint && !bkpt.is_child_breakpoint;

    if (bkpt.is_child_breakpoint) {
      bkpt.parent_breakpoint_number = parseInt(bkpt.number);
    }

    if ("fullname" in breakpoint && breakpoint.fullname) {
      // this is a normal/child breakpoint; gdb gives it the fullname
      bkpt.fullname_to_display = breakpoint.fullname;
    } else if ("original-location" in breakpoint && breakpoint["original-location"]) {
      // this breakpoint is the parent breakpoint of multiple other breakpoints. gdb does not give it
      // the fullname field, but rather the "original-location" field.
      // example breakpoint['original-location']: /home/file.h:19
      // so we need to parse out the line number, and store it
      [bkpt.fullname_to_display, bkpt.line] = Util.parse_fullname_and_line(
        breakpoint["original-location"]
      );
    } else {
      bkpt.fullname_to_display = null;
    }

    // add the breakpoint if it's not stored already
    let bkpts = store.get("breakpoints");
    if (bkpts.indexOf(bkpt) === -1) {
      bkpts.push(bkpt);
      store.set("breakpoints", bkpts);
    }
    return bkpt;
  }
}

export default Breakpoints;


================================================
FILE: gdbgui/src/js/ControlButtons.tsx
================================================
import React from "react";

import Actions from "./Actions";
import GdbApi from "./GdbApi";
import { store } from "statorgfc";

type State = any;

class ControlButtons extends React.Component<{}, State> {
  constructor() {
    // @ts-expect-error ts-migrate(2554) FIXME: Expected 1-2 arguments, but got 0.
    super();
    // @ts-expect-error ts-migrate(2339) FIXME: Property 'connectComponentState' does not exist on... Remove this comment to see the full error message
    store.connectComponentState(this, ["gdb_pid", "reverse_supported"]);
  }
  render() {
    let btn_class = "btn btn-default btn-sm";

    return (
      <React.Fragment>
        <button
          id="run_button"
          onClick={() => GdbApi.click_run_button()}
          type="button"
          title="Start inferior program from the beginning keyboard shortcut: r"
          className={btn_class}
        >
          <span className="glyphicon glyphicon-repeat" />
        </button>

        <button
          id="continue_button"
          onClick={() => GdbApi.click_continue_button()}
          type="button"
          title={
            "Continue until breakpoint is hit or inferior program exits keyboard shortcut: c" +
            (this.state.reverse_supported ? ". shift + c for reverse." : "")
          }
          className={btn_class}
        >
          <span className="glyphicon glyphicon-play" />
        </button>

        <button
          onClick={() => Actions.send_signal("SIGINT", this.state.gdb_pid)}
          type="button"
          title="Send Interrupt signal (SIGINT) to gdb process to pause it (if it's running)"
          className={btn_class}
        >
          <span className="glyphicon glyphicon-pause" />
        </button>

        <button
          id="next_button"
          onClick={() => GdbApi.click_next_button()}
          type="button"
          title={
            "Step over next function call keyboard shortcut: n or right arrow" +
            (this.state.reverse_supported ? ". shift + n for reverse." : "")
          }
          className={btn_class}
        >
          <span className="glyphicon glyphicon-step-forward" />
        </button>

        <button
          id="step_button"
          onClick={() => GdbApi.click_step_button()}
          type="button"
          title={
            "Step into next function call keyboard shortcut: s or down arrow" +
            (this.state.reverse_supported ? ". shift + s for reverse." : "")
          }
          className={btn_class}
        >
          <span className="glyphicon glyphicon-arrow-down" />
        </button>

        <button
          id="return_button"
          onClick={() => GdbApi.click_return_button()}
          type="button"
          title="Step out of current function keyboard shortcut: u or up arrow"
          className={btn_class}
        >
          <span className="glyphicon glyphicon-arrow-up" />
        </button>
        <div role="group" className="btn-group btn-group-xs">
          <button
            id="next_instruction_button"
            onClick={() => GdbApi.click_next_instruction_button()}
            type="button"
            title={
              "Next Instruction: Execute one machine instruction, stepping over function calls keyboard shortcut: m" +
              (this.state.reverse_supported ? ". shift + m for reverse." : "")
            }
            className="btn btn-default"
          >
            NI
          </button>
          <button
            id="step_instruction_button"
            onClick={() => GdbApi.click_step_instruction_button()}
            type="button"
            title={
              "Step Instruction: Execute one machine instruction, stepping into function calls keyboard shortcut: ','" +
              (this.state.reverse_supported ? ". shift + , for reverse." : "")
            }
            className="btn btn-default"
          >
            SI
          </button>
        </div>
      </React.Fragment>
    );
  }
}

export default ControlButtons;


================================================
FILE: gdbgui/src/js/CopyToClipboard.tsx
================================================
import * as React from "react";
import ToolTip from "./ToolTip";
import { store } from "statorgfc";

type Props = {
  content: string | null;
};

class CopyToClipboard extends React.Component<Props> {
  node: HTMLSpanElement | null = null;
  render() {
    if (!this.props.content) {
      return null;
    }
    return (
      <span
        className={"pointer glyphicon glyphicon-book"}
        style={{ color: "#ccc", display: "inline" }}
        ref={node => (this.node = node)}
        onMouseOver={() => {
          ToolTip.show_tooltip_on_node("copy to clipboard", this.node);
        }}
        onMouseLeave={ToolTip.hide_tooltip}
        onClick={() => {
          try {
            let textarea = store.get("textarea_to_copy_to_clipboard");
            
Download .txt
gitextract_zcfu_6aw/

├── .eslintrc.json
├── .flake8
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── build_executable.yml
│       └── tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode/
│   └── settings.json
├── .vulture_whitelist.py
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── docs/
│   ├── CNAME
│   ├── api.md
│   ├── contact.md
│   ├── examples.md
│   ├── faq.md
│   ├── gettingstarted.md
│   ├── guides.md
│   ├── howitworks.md
│   ├── index.md
│   ├── installation.md
│   └── screenshots.md
├── examples/
│   ├── .gitignore
│   ├── README.md
│   ├── c/
│   │   ├── debug_segfault.c
│   │   ├── hello.c
│   │   ├── input.c
│   │   ├── makefile
│   │   ├── sleeper.c
│   │   ├── threads.c
│   │   └── tree.c
│   ├── cpp/
│   │   ├── hello.cpp
│   │   ├── linked_list.cpp
│   │   ├── makefile
│   │   ├── sin.cpp
│   │   └── smart_ptr_demo.cpp
│   ├── fortran/
│   │   ├── fortran_array.f90
│   │   └── makefile
│   ├── golang/
│   │   ├── hello.go
│   │   └── makefile
│   └── rust/
│       ├── .gitignore
│       ├── Cargo.toml
│       ├── README.md
│       ├── compile_and_debug.sh
│       └── src/
│           └── main.rs
├── gdbgui/
│   ├── SSLify.py
│   ├── VERSION.txt
│   ├── __init__.py
│   ├── __main__.py
│   ├── cli.py
│   ├── htmllistformatter.py
│   ├── py.typed
│   ├── server/
│   │   ├── __init__.py
│   │   ├── app.py
│   │   ├── constants.py
│   │   ├── http_routes.py
│   │   ├── http_util.py
│   │   ├── ptylib.py
│   │   ├── server.py
│   │   └── sessionmanager.py
│   ├── src/
│   │   └── js/
│   │       ├── Actions.ts
│   │       ├── BinaryLoader.tsx
│   │       ├── Breakpoints.tsx
│   │       ├── ControlButtons.tsx
│   │       ├── CopyToClipboard.tsx
│   │       ├── Expressions.tsx
│   │       ├── FileOps.tsx
│   │       ├── FileSystem.tsx
│   │       ├── FoldersView.tsx
│   │       ├── GdbApi.tsx
│   │       ├── GdbMiOutput.tsx
│   │       ├── GdbVariable.tsx
│   │       ├── GdbguiModal.tsx
│   │       ├── GlobalEvents.ts
│   │       ├── HoverVar.tsx
│   │       ├── InferiorProgramInfo.tsx
│   │       ├── InitialStoreData.ts
│   │       ├── Links.tsx
│   │       ├── Locals.tsx
│   │       ├── Memory.tsx
│   │       ├── MemoryLink.tsx
│   │       ├── MiddleLeft.tsx
│   │       ├── ReactTable.tsx
│   │       ├── Registers.tsx
│   │       ├── RightSidebar.tsx
│   │       ├── Settings.tsx
│   │       ├── SourceCode.tsx
│   │       ├── SourceCodeHeading.tsx
│   │       ├── SourceFileAutocomplete.tsx
│   │       ├── StatusBar.tsx
│   │       ├── Terminals.tsx
│   │       ├── Threads.tsx
│   │       ├── ToolTip.tsx
│   │       ├── ToolTipTourguide.tsx
│   │       ├── TopBar.tsx
│   │       ├── Tree.ts
│   │       ├── Util.ts
│   │       ├── constants.ts
│   │       ├── dashboard.tsx
│   │       ├── gdbgui.tsx
│   │       ├── processFeatures.ts
│   │       ├── process_gdb_response.tsx
│   │       ├── register_descriptions.ts
│   │       ├── tests/
│   │       │   └── Util.jest.ts
│   │       └── types.d.ts
│   ├── static/
│   │   ├── css/
│   │   │   ├── gdbgui.css
│   │   │   ├── splitjs-gdbgui.css
│   │   │   └── tailwind.css
│   │   └── vendor/
│   │       ├── css/
│   │       │   ├── animate.css
│   │       │   ├── gdbgui_awesomeplete.css
│   │       │   └── pygments/
│   │       │       ├── emacs.css
│   │       │       ├── light.css
│   │       │       ├── monokai.css
│   │       │       └── vim.css
│   │       └── js/
│   │           └── splitjs.min-1.2.0.js
│   └── templates/
│       ├── dashboard.html
│       └── gdbgui.html
├── images/
│   ├── gdbgui.xcf
│   ├── gdbgui_small.xcf
│   └── gdbgui_square.xcf
├── jest.config.js
├── make_executable.py
├── mkdocs.yml
├── noxfile.py
├── package.json
├── postcss.config.js
├── requirements.in
├── requirements.txt
├── setup.py
├── tailwind.config.js
├── tests/
│   ├── __init__.py
│   ├── test_backend.py
│   ├── test_cli.py
│   ├── test_ptylib.py
│   └── test_sessionmanager.py
├── tsconfig.json
├── tslint.json
└── webpack.config.js
Download .txt
SYMBOL INDEX (463 symbols across 66 files)

FILE: examples/c/debug_segfault.c
  function main (line 5) | int main(void)

FILE: examples/c/hello.c
  function say_something (line 3) | void say_something(const char *str)
  type mystruct_t (line 8) | struct mystruct_t
  function main (line 32) | int main(int argc, char **argv)

FILE: examples/c/input.c
  function main (line 4) | int main(int argc, char **argv)

FILE: examples/c/sleeper.c
  function main (line 5) | int main(int argc, char **argv) {

FILE: examples/c/threads.c
  function main (line 17) | int main()

FILE: examples/c/tree.c
  type Node (line 5) | struct Node
  function visit (line 12) | void visit(struct Node* node)
  function dfs (line 17) | void dfs(struct Node *node)
  function main (line 29) | int main(void)

FILE: examples/cpp/hello.cpp
  function main (line 5) | int main(void)

FILE: examples/cpp/linked_list.cpp
  class Node (line 3) | class Node{
    method Node (line 11) | Node(int v){
    method get_value (line 15) | int get_value() const{
    method print_values (line 19) | void print_values() const{
    method append (line 26) | void append(int v){
  function main (line 37) | int main(){

FILE: examples/cpp/sin.cpp
  function main (line 3) | int main ()

FILE: examples/cpp/smart_ptr_demo.cpp
  class SimpleType (line 33) | class SimpleType
    method SimpleType (line 38) | SimpleType(const std::string& ptr_type){
    method identify (line 45) | void identify(){
  function main (line 50) | int main()

FILE: examples/golang/hello.go
  function main (line 4) | func main() {

FILE: examples/rust/src/main.rs
  function analyze_slice (line 4) | fn analyze_slice(slice: &[i32]) {
  function main (line 9) | fn main() {

FILE: gdbgui/SSLify.py
  class SSLify (line 13) | class SSLify(object):
    method __init__ (line 16) | def __init__(
    method init_app (line 29) | def init_app(self, app):
    method hsts_header (line 45) | def hsts_header(self):
    method skip (line 55) | def skip(self):
    method redirect_to_ssl (line 64) | def redirect_to_ssl(self):
    method set_hsts_header (line 83) | def set_hsts_header(self, response):
  function get_ssl_context (line 91) | def get_ssl_context(private_key, certificate):

FILE: gdbgui/cli.py
  function get_gdbgui_auth_user_credentials (line 27) | def get_gdbgui_auth_user_credentials(auth_file, user, password):
  function warn_startup_with_shell_off (line 54) | def warn_startup_with_shell_off(platform: str, gdb_args: str):
  function get_parser (line 68) | def get_parser():
  function get_initial_binary_and_args (line 189) | def get_initial_binary_and_args(
  function main (line 200) | def main():

FILE: gdbgui/htmllistformatter.py
  class HtmlListFormatter (line 4) | class HtmlListFormatter(HtmlFormatter):
    method get_marked_up_list (line 9) | def get_marked_up_list(self, tokensource):

FILE: gdbgui/server/app.py
  function csrf_protect_all_post_and_cross_origin_requests (line 35) | def csrf_protect_all_post_and_cross_origin_requests():
  function client_connected (line 55) | def client_connected():
  function pty_interaction (line 133) | def pty_interaction(message):
  function run_gdb_command (line 168) | def run_gdb_command(message: Dict[str, str]):
  function send_msg_to_clients (line 196) | def send_msg_to_clients(client_ids, msg, error=False):
  function client_disconnected (line 213) | def client_disconnected():
  function test_disconnect (line 220) | def test_disconnect():
  function read_and_forward_gdb_and_pty_output (line 224) | def read_and_forward_gdb_and_pty_output():
  function check_and_forward_pty_output (line 270) | def check_and_forward_pty_output() -> List[DebugSession]:

FILE: gdbgui/server/constants.py
  function colorize (line 24) | def colorize(text):

FILE: gdbgui/server/http_routes.py
  function read_file (line 33) | def read_file():
  function get_last_modified_unix_sec (line 109) | def get_last_modified_unix_sec():
  function help_route (line 125) | def help_route():
  function dashboard (line 131) | def dashboard():
  function gdbgui (line 149) | def gdbgui():
  function dashboard_data (line 180) | def dashboard_data():
  function kill_session (line 188) | def kill_session():
  function send_signal_to_pid (line 203) | def send_signal_to_pid():

FILE: gdbgui/server/http_util.py
  function add_csrf_token_to_session (line 11) | def add_csrf_token_to_session():
  function is_cross_origin (line 16) | def is_cross_origin(request):
  function csrf_protect (line 35) | def csrf_protect(f):
  function client_error (line 51) | def client_error(obj):
  function authenticate (line 55) | def authenticate(f):
  function credentials_are_valid (line 77) | def credentials_are_valid(username, password):

FILE: gdbgui/server/ptylib.py
  class Pty (line 19) | class Pty:
    method __init__ (line 22) | def __init__(self, *, cmd: Optional[str] = None, echo: bool = True):
    method set_echo (line 51) | def set_echo(self, echo_on: bool) -> None:
    method set_winsize (line 63) | def set_winsize(self, rows: int, cols: int):
    method read (line 71) | def read(self) -> Optional[str]:
    method write (line 84) | def write(self, data: str):

FILE: gdbgui/server/server.py
  function get_ssl_context (line 12) | def get_ssl_context(private_key, certificate):  # noqa
  function get_extra_files (line 16) | def get_extra_files():
  function run_server (line 35) | def run_server(

FILE: gdbgui/server/sessionmanager.py
  class DebugSession (line 16) | class DebugSession:
    method __init__ (line 17) | def __init__(
    method terminate (line 38) | def terminate(self):
    method to_dict (line 47) | def to_dict(self):
    method add_client (line 56) | def add_client(self, client_id: str):
    method remove_client (line 59) | def remove_client(self, client_id: str):
  class SessionManager (line 65) | class SessionManager(object):
    method __init__ (line 66) | def __init__(self):
    method connect_client_to_debug_session (line 73) | def connect_client_to_debug_session(
    method add_new_debug_session (line 84) | def add_new_debug_session(
    method remove_debug_session_by_pid (line 118) | def remove_debug_session_by_pid(self, gdbpid: int) -> List[str]:
    method remove_debug_session (line 127) | def remove_debug_session(self, debug_session: DebugSession) -> List[str]:
    method remove_debug_sessions_with_no_clients (line 136) | def remove_debug_sessions_with_no_clients(self) -> None:
    method get_pid_from_debug_session (line 144) | def get_pid_from_debug_session(self, debug_session: DebugSession) -> O...
    method debug_session_from_pid (line 149) | def debug_session_from_pid(self, pid: int) -> Optional[DebugSession]:
    method debug_session_from_client_id (line 156) | def debug_session_from_client_id(self, client_id: str) -> Optional[Deb...
    method get_dashboard_data (line 162) | def get_dashboard_data(self) -> List[DebugSession]:
    method disconnect_client (line 168) | def disconnect_client(self, client_id: str):

FILE: gdbgui/src/js/Actions.ts
  method add_gdb_response_to_console (line 104) | add_gdb_response_to_console(mi_obj: any) {
  method toggle_modal_visibility (line 139) | toggle_modal_visibility() {
  method show_modal (line 142) | show_modal(header: any, body: any) {
  method set_gdb_binary_and_arguments (line 147) | set_gdb_binary_and_arguments(binary: any, args: any) {
  method connect_to_gdbserver (line 157) | connect_to_gdbserver(user_input: any) {
  method remote_connected (line 165) | remote_connected() {
  method attach_to_process (line 184) | attach_to_process(user_input: any) {
  method fetch_source_files (line 188) | fetch_source_files() {
  method view_file (line 192) | view_file(fullname: any, line: any) {
  method set_line_state (line 197) | set_line_state(line: any) {
  method clear_cached_assembly (line 206) | clear_cached_assembly() {
  method update_max_lines_of_code_to_fetch (line 214) | update_max_lines_of_code_to_fetch(new_value: any) {
  method send_signal (line 221) | send_signal(signal_name: any, pid: any) {

FILE: gdbgui/src/js/BinaryLoader.tsx
  constant TARGET_TYPES (line 7) | const TARGET_TYPES = {
  type State (line 14) | type State = any;
  class BinaryLoader (line 20) | class BinaryLoader extends React.Component<{}, State> {
    method constructor (line 21) | constructor(props: {}) {
    method render (line 49) | render() {
    method componentDidMount (line 175) | componentDidMount() {
    method onkeyup_user_input (line 181) | onkeyup_user_input(e: any) {
    method onchange_user_inpu (line 186) | onchange_user_inpu(e: any) {
    method click_set_target_app (line 195) | click_set_target_app() {
    method _add_user_input_to_history (line 199) | _add_user_input_to_history(binary_and_args: any) {
    method _parse_binary_and_args_from_user_input (line 219) | _parse_binary_and_args_from_user_input(user_input: any) {
    method set_target_app (line 232) | set_target_app() {

FILE: gdbgui/src/js/Breakpoints.tsx
  type BreakpointState (line 35) | type BreakpointState = any;
  class Breakpoint (line 37) | class Breakpoint extends React.Component<{}, BreakpointState> {
    method constructor (line 38) | constructor(props: {}) {
    method get_source_line (line 45) | get_source_line(fullname: any, linenum: any) {
    method get_delete_jsx (line 72) | get_delete_jsx(bkpt_num_to_delete: any) {
    method get_num_times_hit (line 87) | get_num_times_hit(bkpt: any) {
    method on_change_bkpt_cond (line 99) | on_change_bkpt_cond(e: any) {
    method on_key_up_bktp_cond (line 105) | on_key_up_bktp_cond(number: any, e: any) {
    method on_break_cond_click (line 111) | on_break_cond_click(e: any) {
    method render (line 116) | render() {
  class Breakpoints (line 264) | class Breakpoints extends React.Component {
    method constructor (line 265) | constructor() {
    method render (line 271) | render() {
    method enable_or_disable_bkpt (line 284) | static enable_or_disable_bkpt(checked: any, bkpt_num: any) {
    method set_breakpoint_condition (line 291) | static set_breakpoint_condition(condition: any, bkpt_num: any) {
    method remove_breakpoint_if_present (line 297) | static remove_breakpoint_if_present(fullname: any, line: any) {
    method add_or_remove_breakpoint (line 304) | static add_or_remove_breakpoint(fullname: any, line: any) {
    method add_breakpoint (line 311) | static add_breakpoint(fullname: any, line: any) {
    method has_breakpoint (line 314) | static has_breakpoint(fullname: any, line: any) {
    method get_breakpoint_number (line 323) | static get_breakpoint_number(fullname: any, line: any) {
    method delete_breakpoint (line 332) | static delete_breakpoint(breakpoint_number: any) {
    method get_breakpoint_lines_for_file (line 338) | static get_breakpoint_lines_for_file(fullname: any) {
    method get_disabled_breakpoint_lines_for_file (line 344) | static get_disabled_breakpoint_lines_for_file(fullname: any) {
    method get_conditional_breakpoint_lines_for_file (line 350) | static get_conditional_breakpoint_lines_for_file(fullname: any) {
    method save_breakpoints (line 356) | static save_breakpoints(payload: any) {
    method save_breakpoint (line 364) | static save_breakpoint(breakpoint: any) {

FILE: gdbgui/src/js/ControlButtons.tsx
  type State (line 7) | type State = any;
  class ControlButtons (line 9) | class ControlButtons extends React.Component<{}, State> {
    method constructor (line 10) | constructor() {
    method render (line 16) | render() {

FILE: gdbgui/src/js/CopyToClipboard.tsx
  type Props (line 5) | type Props = {
  class CopyToClipboard (line 9) | class CopyToClipboard extends React.Component<Props> {
    method render (line 11) | render() {

FILE: gdbgui/src/js/Expressions.tsx
  class Expressions (line 6) | class Expressions extends React.Component {
    method constructor (line 9) | constructor() {
    method render (line 16) | render() {
    method componentDidUpdate (line 75) | componentDidUpdate() {
    method keydown_on_input (line 81) | static keydown_on_input(e: any) {

FILE: gdbgui/src/js/FileOps.tsx
  method fetch_complete (line 113) | fetch_complete() {
  method get_start_and_end_lines (line 231) | get_start_and_end_lines(
  method update_source_code_state (line 267) | update_source_code_state(
  method show_modal_if_file_modified_after_binary (line 423) | show_modal_if_file_modified_after_binary(
  method fetch_more_source_at_beginning (line 471) | fetch_more_source_at_beginning() {
  method fetch_more_source_at_end (line 497) | fetch_more_source_at_end() {

FILE: gdbgui/src/js/FileSystem.tsx
  class FileSystem (line 3) | class FileSystem extends React.Component {
    method get_node_jsx (line 5) | get_node_jsx(node: any, depth = 0) {
    method render (line 54) | render() {

FILE: gdbgui/src/js/FoldersView.tsx
  function get_child_node_with_name (line 15) | function get_child_node_with_name(name: any, curnode: any) {
  type State (line 27) | type State = any;
  class FoldersView (line 29) | class FoldersView extends React.Component<{}, State> {
    method constructor (line 32) | constructor(props: {}) {
    method render (line 54) | render() {
    method onClickName (line 120) | onClickName(node: any) {
    method reveal_path (line 137) | reveal_path(path: any) {
    method update_filesystem_data (line 168) | update_filesystem_data(keys: any) {
    method onToggle (line 230) | onToggle(node: any) {
    method expand_all (line 234) | expand_all() {
    method collapse_all (line 243) | collapse_all() {
    method _dfs (line 252) | _dfs(node: any, callback: any) {

FILE: gdbgui/src/js/GdbApi.tsx
  method get_inferior_binary_last_modified_unix_sec (line 383) | get_inferior_binary_last_modified_unix_sec(path: any) {
  method get_load_binary_and_arguments_cmds (line 405) | get_load_binary_and_arguments_cmds(binary: any, args: any) {
  method set_assembly_flavor (line 418) | set_assembly_flavor(flavor: string) {
  method _recieve_last_modified_unix_sec (line 421) | _recieve_last_modified_unix_sec(data: { path: any; last_modified_unix_se...
  method _error_getting_last_modified_unix_sec (line 429) | _error_getting_last_modified_unix_sec(data: any) {

FILE: gdbgui/src/js/GdbMiOutput.tsx
  type State (line 12) | type State = any;
  class GdbMiOutput (line 14) | class GdbMiOutput extends React.Component<{}, State> {
    method constructor (line 18) | constructor() {
    method render (line 32) | render() {
    method componentDidMount (line 49) | componentDidMount() {
    method componentDidUpdate (line 52) | componentDidUpdate() {
    method _scroll_to_bottom (line 55) | _scroll_to_bottom() {
    method add_mi_output (line 58) | static add_mi_output(mi_obj: any) {

FILE: gdbgui/src/js/GdbVariable.tsx
  method fetch_children (line 39) | fetch_children(expr_of_parent: any, expr_type: any) {
  method fetch_complete (line 44) | fetch_complete() {
  method created_variable (line 112) | created_variable(r: any) {
  method fetch_failed (line 135) | fetch_failed(r: any) {
  method _fetch_complete (line 143) | _fetch_complete() {
  class GdbVariable (line 153) | class GdbVariable extends React.Component {
    method render (line 154) | render() {
    method get_ul_for_local (line 194) | get_ul_for_local(local: any) {
    method get_ul_for_var_with_children (line 220) | get_ul_for_var_with_children(
    method get_ul_for_var_without_children (line 264) | get_ul_for_var_without_children(
    method _get_value_jsx (line 272) | static _get_value_jsx(obj: any) {
    method change_radix (line 300) | static change_radix(obj: any) {
    method _get_ul_for_var (line 312) | _get_ul_for_var(
    method _get_full_path (line 399) | static _get_full_path(obj: any) {
    method create_variable (line 435) | static create_variable(expression: any, expr_type: any) {
    method gdb_created_root_variable (line 438) | static gdb_created_root_variable(r: any) {
    method gdb_variable_fetch_failed (line 441) | static gdb_variable_fetch_failed(r: any) {
    method gdb_created_children_variables (line 450) | static gdb_created_children_variables(r: any) {
    method prepare_gdb_obj_for_storage (line 513) | static prepare_gdb_obj_for_storage(obj: any, parent: any) {
    method _update_numeric_properties (line 559) | static _update_numeric_properties(obj: any) {
    method _update_radix_values (line 569) | static _update_radix_values(obj: any) {
    method _make_plot (line 587) | static _make_plot(obj: any) {
    method plot_var_and_children (line 639) | static plot_var_and_children(obj: any) {
    method fetch_and_show_children_for_var (line 647) | static fetch_and_show_children_for_var(gdb_var_name: any) {
    method hide_children_in_ui (line 661) | static hide_children_in_ui(gdb_var_name: any) {
    method click_toggle_children_visibility (line 669) | static click_toggle_children_visibility(gdb_variable_name: any) {
    method _toggle_children_visibility (line 672) | static _toggle_children_visibility(gdb_var_name: any) {
    method click_toggle_plot (line 692) | static click_toggle_plot(gdb_var_name: any) {
    method get_update_cmds (line 701) | static get_update_cmds() {
    method handle_changelist (line 716) | static handle_changelist(changelist_array: any) {
    method click_draw_tree_gdb_variable (line 745) | static click_draw_tree_gdb_variable(gdb_variable: any) {
    method delete_gdb_variable (line 748) | static delete_gdb_variable(gdbvar: any) {
    method _delete_local_gdb_var_data (line 758) | static _delete_local_gdb_var_data(gdb_var_name: any) {
    method save_new_expression (line 767) | static save_new_expression(expression: any, expr_type: any, obj: any) {
    method get_child_with_name (line 777) | static get_child_with_name(children: any, name: any) {
    method get_root_name_from_gdbvar_name (line 785) | static get_root_name_from_gdbvar_name(gdb_var_name: any) {
    method get_child_names_from_gdbvar_name (line 793) | static get_child_names_from_gdbvar_name(gdb_var_name: any) {
    method get_obj_from_gdb_var_name (line 808) | static get_obj_from_gdb_var_name(expressions: any, gdb_var_name: any) {

FILE: gdbgui/src/js/GdbguiModal.tsx
  type State (line 5) | type State = any;
  class Modal (line 7) | class Modal extends React.Component<{}, State> {
    method constructor (line 9) | constructor() {
    method render (line 15) | render() {

FILE: gdbgui/src/js/HoverVar.tsx
  class HoverVar (line 11) | class HoverVar extends React.Component {
    method constructor (line 19) | constructor() {
    method render (line 37) | render() {
    method mouseover_variable (line 67) | static mouseover_variable(e: any) {
    method mouseout_variable (line 87) | static mouseout_variable(e: any) {
    method mouseover_hover_window (line 95) | static mouseover_hover_window(e: any) {
    method mouseout_hover_window (line 102) | static mouseout_hover_window(e: any) {
    method clear_hover_state (line 106) | static clear_hover_state() {

FILE: gdbgui/src/js/InferiorProgramInfo.tsx
  type State (line 6) | type State = any;
  class InferiorProgramInfo (line 8) | class InferiorProgramInfo extends React.Component<{}, State> {
    method constructor (line 9) | constructor() {
    method get_li_for_signal (line 21) | get_li_for_signal(s: any, signal_key: any) {
    method get_signal_choices (line 37) | get_signal_choices(signal_key: any) {
    method get_dropdown (line 54) | get_dropdown() {
    method render (line 73) | render() {

FILE: gdbgui/src/js/InitialStoreData.ts
  function get_stored (line 118) | function get_stored(key: any, default_val: any) {

FILE: gdbgui/src/js/Links.tsx
  type Props (line 6) | type Props = {
  class FileLink (line 13) | class FileLink extends React.Component<Props> {
    method render (line 14) | render() {
  type FrameLinkProps (line 54) | type FrameLinkProps = {
  class FrameLink (line 61) | class FrameLink extends React.Component<FrameLinkProps> {
    method render (line 62) | render() {

FILE: gdbgui/src/js/Locals.tsx
  class Locals (line 10) | class Locals extends React.Component {
    method constructor (line 11) | constructor() {
    method render (line 17) | render() {
    method get_autocreated_obj_from_expr (line 60) | get_autocreated_obj_from_expr(expr: any) {
    method clear_autocreated_exprs (line 68) | static clear_autocreated_exprs() {
    method clear (line 74) | static clear() {
    method save_locals (line 78) | static save_locals(locals: any) {
    method can_local_be_expanded (line 86) | static can_local_be_expanded(local: any) {

FILE: gdbgui/src/js/Memory.tsx
  type State (line 17) | type State = any;
  class Memory (line 19) | class Memory extends React.Component<{}, State> {
    method constructor (line 24) | constructor() {
    method get_memory_component_jsx_content (line 35) | get_memory_component_jsx_content() {
    method render (line 125) | render() {
    method keypress_on_input (line 173) | static keypress_on_input(e: any) {
    method set_inputs_from_address (line 178) | static set_inputs_from_address(addr: any) {
    method get_gdb_commands_from_state (line 188) | static get_gdb_commands_from_state() {
    method fetch_memory_from_state (line 235) | static fetch_memory_from_state() {
    method click_read_preceding_memory (line 241) | static click_read_preceding_memory() {
    method click_read_more_memory (line 251) | static click_read_more_memory() {
    method make_addrs_into_links_react (line 265) | static make_addrs_into_links_react(text: any) {
    method add_value_to_cache (line 288) | static add_value_to_cache(hex_str: any, hex_val: any) {
    method clear_cache (line 298) | static clear_cache() {

FILE: gdbgui/src/js/MemoryLink.tsx
  type OwnProps (line 4) | type OwnProps = {
  type Props (line 9) | type Props = OwnProps & typeof MemoryLink.defaultProps;
  class MemoryLink (line 11) | class MemoryLink extends React.Component<Props> {
    method render (line 12) | render() {

FILE: gdbgui/src/js/MiddleLeft.tsx
  class MiddleLeft (line 9) | class MiddleLeft extends React.Component {
    method constructor (line 13) | constructor() {
    method render (line 20) | render() {
    method componentDidMount (line 31) | componentDidMount() {
    method onscroll_container (line 40) | onscroll_container() {
    method check_to_autofetch_more_source (line 45) | check_to_autofetch_more_source() {

FILE: gdbgui/src/js/ReactTable.tsx
  class TableRow (line 3) | class TableRow extends React.Component {
    method get_tds (line 5) | get_tds() {
    method render (line 15) | render() {
  class ReactTable (line 20) | class ReactTable extends React.Component {
    method render_row (line 22) | render_row(row_data: any, i: any) {
    method render_head (line 27) | render_head() {
    method render (line 38) | render() {

FILE: gdbgui/src/js/Registers.tsx
  constant MAX_REGISTER_NAME_FETCH_COUNT (line 13) | const MAX_REGISTER_NAME_FETCH_COUNT = 5;
  type State (line 17) | type State = any;
  class Registers (line 19) | class Registers extends React.Component<{}, State> {
    method constructor (line 20) | constructor() {
    method get_update_cmds (line 32) | static get_update_cmds() {
    method cache_register_names (line 62) | static cache_register_names(names: any) {
    method clear_register_name_cache (line 69) | static clear_register_name_cache() {
    method clear_cached_values (line 72) | static clear_cached_values() {
    method inferior_program_exited (line 76) | static inferior_program_exited() {
    method render (line 79) | render() {

FILE: gdbgui/src/js/RightSidebar.tsx
  type OwnCollapserState (line 34) | type OwnCollapserState = any;
  type CollapserState (line 36) | type CollapserState = OwnCollapserState & typeof Collapser.defaultProps;
  class Collapser (line 38) | class Collapser extends React.Component<{}, CollapserState> {
    method constructor (line 44) | constructor(props: {}) {
    method toggle_visibility (line 63) | toggle_visibility() {
    method onmousedown_resizer (line 66) | onmousedown_resizer(e: any) {
    method onmouseup_resizer (line 71) | onmouseup_resizer() {
    method onmousemove_resizer (line 74) | onmousemove_resizer(e: any) {
    method onclick_restore_autosize (line 83) | onclick_restore_autosize() {
    method render (line 86) | render() {
  class RightSidebar (line 163) | class RightSidebar extends React.Component {
    method render (line 164) | render() {
    method componentDidMount (line 261) | componentDidMount() {

FILE: gdbgui/src/js/Settings.tsx
  class Settings (line 9) | class Settings extends React.Component {
    method constructor (line 13) | constructor() {
    method toggle_key (line 34) | static toggle_key(key: any) {
    method get_checkbox_row (line 38) | static get_checkbox_row(store_key: any, text: any) {
    method get_update_max_lines_of_code_to_fetch (line 56) | get_update_max_lines_of_code_to_fetch() {
    method get_table (line 81) | get_table() {
    method render (line 128) | render() {

FILE: gdbgui/src/js/SourceCode.tsx
  type State (line 14) | type State = any;
  class SourceCode (line 16) | class SourceCode extends React.Component<{}, State> {
    method constructor (line 23) | constructor() {
    method render (line 54) | render() {
    method componentDidUpdate (line 68) | componentDidUpdate() {
    method get_body (line 83) | get_body() {
    method click_gutter (line 155) | click_gutter(line_num: any) {
    method _get_source_line (line 159) | _get_source_line(
    method get_linenum_td (line 226) | get_linenum_td(linenum: any, gutter_cls = "") {
    method _get_assm_content (line 243) | static _get_assm_content(key: any, assm: any, paused_addr: any) {
    method _get_assm_row (line 280) | _get_assm_row(key: any, assm: any, paused_addr: any) {
    method is_gdb_paused_on_this_line (line 290) | is_gdb_paused_on_this_line(line_num_being_rendered: any, line_gdb_is_p...
    method get_view_more_tr (line 300) | get_view_more_tr(fullname: any, linenum: any, node_key: any) {
    method get_end_of_file_tr (line 317) | get_end_of_file_tr(linenum: any) {
    method get_line_nums_to_render (line 327) | get_line_nums_to_render(
    method get_body_source_and_assm (line 359) | get_body_source_and_assm(
    method get_body_assembly_only (line 458) | get_body_assembly_only(assm_array: any, paused_addr: any) {
    method get_body_empty (line 468) | get_body_empty() {
    method make_current_line_visible (line 475) | static make_current_line_visible() {
    method is_source_line_visible (line 478) | static is_source_line_visible(jq_selector: any) {
    method _make_jq_selector_visible (line 506) | static _make_jq_selector_visible(jq_selector: any) {

FILE: gdbgui/src/js/SourceCodeHeading.tsx
  type State (line 7) | type State = any;
  class SourceCodeHeading (line 9) | class SourceCodeHeading extends React.Component<{}, State> {
    method constructor (line 10) | constructor() {
    method render (line 21) | render() {

FILE: gdbgui/src/js/SourceFileAutocomplete.tsx
  class SourceFileAutocomplete (line 16) | class SourceFileAutocomplete extends React.Component {
    method constructor (line 19) | constructor() {
    method store_change_callback (line 25) | store_change_callback() {
    method render (line 31) | render() {
    method keyup_source_file_input (line 57) | keyup_source_file_input(e: any) {
    method onclick_dropdown (line 77) | onclick_dropdown() {
    method componentDidMount (line 93) | componentDidMount() {

FILE: gdbgui/src/js/StatusBar.tsx
  type State (line 5) | type State = any;
  class StatusBar (line 10) | class StatusBar extends React.Component<{}, State> {
    method render (line 11) | render() {

FILE: gdbgui/src/js/Terminals.tsx
  function customKeyEventHandler (line 10) | function customKeyEventHandler(config: {
  class Terminals (line 42) | class Terminals extends React.Component {
    method constructor (line 46) | constructor(props: any) {
    method terminal (line 54) | terminal(ref: React.RefObject<any>) {
    method render (line 62) | render() {
    method componentDidMount (line 74) | componentDidMount() {

FILE: gdbgui/src/js/Threads.tsx
  class FrameArguments (line 9) | class FrameArguments extends React.Component {
    method render_frame_arg (line 10) | render_frame_arg(frame_arg: any) {
    method render (line 14) | render() {
  type ThreadsState (line 31) | type ThreadsState = any;
  class Threads (line 33) | class Threads extends React.Component<{}, ThreadsState> {
    method constructor (line 34) | constructor() {
    method select_thread_id (line 46) | static select_thread_id(thread_id: any) {
    method select_frame (line 50) | static select_frame(framenum: any) {
    method render (line 57) | render() {
    method get_stack_for_thread (line 100) | static get_stack_for_thread(
    method get_thread_header (line 118) | static get_thread_header(thread: any, is_current_thread_being_rendered...
    method get_frame_row (line 160) | static get_frame_row(
    method get_row_data_for_stack (line 203) | static get_row_data_for_stack(
    method update_stack (line 231) | static update_stack(stack: any) {
    method set_thread_id (line 242) | set_thread_id(id: any) {

FILE: gdbgui/src/js/ToolTip.tsx
  class ToolTip (line 4) | class ToolTip extends React.Component {
    method constructor (line 6) | constructor() {
    method hide_tooltip (line 13) | static hide_tooltip() {
    method show_tooltip_on_node (line 21) | static show_tooltip_on_node(content: any, node: any, show_for_n_sec = ...
    method show_copied_tooltip_on_node (line 29) | static show_copied_tooltip_on_node(node: any) {
    method render (line 33) | render() {

FILE: gdbgui/src/js/ToolTipTourguide.tsx
  type State (line 5) | type State = any;
  class ToolTipTourguide (line 7) | class ToolTipTourguide extends React.Component<{}, State> {
    method constructor (line 8) | constructor(props: {}) {
    method componentWillMount (line 23) | componentWillMount() {
    method dismiss (line 26) | static dismiss() {
    method next (line 31) | static next() {
    method guide_finshed (line 34) | guide_finshed() {
    method start_guide (line 37) | static start_guide() {
    method componentDidUpdate (line 42) | componentDidUpdate() {
    method get_position (line 51) | get_position(position_name: any) {
    method render (line 88) | render() {

FILE: gdbgui/src/js/TopBar.tsx
  type State (line 167) | type State = any;
  class TopBar (line 169) | class TopBar extends React.Component<{}, State> {
    method constructor (line 172) | constructor() {
    method store_update_callback (line 199) | store_update_callback(keys: any) {
    method _set_spinner_timeout (line 209) | _set_spinner_timeout() {
    method _clear_spinner_timeout (line 216) | _clear_spinner_timeout() {
    method toggle_assembly_flavor (line 219) | toggle_assembly_flavor() {
    method get_controls (line 226) | get_controls() {
    method render (line 260) | render() {
    method needs_to_update_gdbgui_version (line 446) | static needs_to_update_gdbgui_version() {

FILE: gdbgui/src/js/Util.ts
  method string_to_array_safe_quotes (line 88) | string_to_array_safe_quotes(str: any) {
  method is_newer (line 122) | is_newer(latest: any, current: any) {

FILE: gdbgui/src/js/dashboard.tsx
  type GdbguiSession (line 5) | type GdbguiSession = {
  function GdbguiSession (line 27) | function GdbguiSession(props: { session: GdbguiSession; updateData: Func...
  function redirect (line 95) | function redirect(url: string) {
  class StartCommand (line 99) | class StartCommand extends React.Component<any, { value: string }> {
    method constructor (line 100) | constructor(props: any) {
    method handleChange (line 109) | handleChange(event: any) {
    method handleSubmit (line 113) | handleSubmit() {
    method render (line 120) | render() {
  function Nav (line 150) | function Nav() {
  class Dashboard (line 194) | class Dashboard extends React.PureComponent<any, { sessions: GdbguiSessi...
    method constructor (line 196) | constructor(props: any) {
    method updateData (line 201) | async updateData() {
    method componentDidMount (line 206) | componentDidMount() {
    method componentWillUnmount (line 209) | componentWillUnmount() {
    method render (line 214) | render() {

FILE: gdbgui/src/js/gdbgui.tsx
  class Gdbgui (line 59) | class Gdbgui extends React.PureComponent {
    method componentWillMount (line 60) | componentWillMount() {
    method render (line 65) | render() {
    method componentDidMount (line 129) | componentDidMount() {

FILE: gdbgui/src/js/processFeatures.ts
  type Feature (line 4) | type Feature =
  function processFeatures (line 20) | function processFeatures(features: Array<Feature>) {

FILE: make_executable.py
  function write_spec_with_gdbgui_version_in_name (line 18) | def write_spec_with_gdbgui_version_in_name(spec_path, binary_name):
  function verify (line 67) | def verify(binary_path: str, version: str):
  function generate_md5 (line 77) | def generate_md5(binary: Path, output_file: Path):
  function main (line 84) | def main():

FILE: noxfile.py
  function python_tests (line 38) | def python_tests(session):
  function js_tests (line 48) | def js_tests(session):
  function tests (line 55) | def tests(session):
  function cover (line 61) | def cover(session):
  function vulture (line 75) | def vulture(session):
  function lint (line 89) | def lint(session):
  function autoformat (line 103) | def autoformat(session):
  function docs (line 110) | def docs(session):
  function develop (line 116) | def develop(session):
  function serve (line 125) | def serve(session):
  function build (line 131) | def build(session):
  function publish (line 145) | def publish(session):
  function watch_docs (line 154) | def watch_docs(session):
  function publish_docs (line 160) | def publish_docs(session):
  function build_executables_current_platform (line 166) | def build_executables_current_platform(session):
  function build_executables_mac (line 175) | def build_executables_mac(session):
  function build_executables_linux (line 182) | def build_executables_linux(session):
  function build_executable_windows (line 189) | def build_executable_windows(session):
  function build_pex (line 196) | def build_pex(session):

FILE: tests/test_backend.py
  function test_connect (line 11) | def test_connect():
  function test_client (line 26) | def test_client():
  function test_load_main_page (line 30) | def test_load_main_page(test_client):
  function test_load_dashboard (line 36) | def test_load_dashboard(test_client):
  function test_cant_load_bad_url (line 42) | def test_cant_load_bad_url(test_client):
  function test_same_port (line 48) | def test_same_port():
  function test_get_initial_binary_and_args (line 52) | def test_get_initial_binary_and_args():

FILE: tests/test_cli.py
  function run_gdbgui_cli (line 9) | def run_gdbgui_cli(gdbgui_args: List[str]):
  function test_cli_fails (line 35) | def test_cli_fails(monkeypatch, argv):
  function test_cli_help (line 45) | def test_cli_help(monkeypatch):

FILE: tests/test_ptylib.py
  function test_pty (line 6) | def test_pty():

FILE: tests/test_sessionmanager.py
  function test_SessionManager (line 4) | def test_SessionManager():
Condensed preview — 143 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (570K chars).
[
  {
    "path": ".eslintrc.json",
    "chars": 477,
    "preview": "{\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true,\n    \"jquery\": true\n  },\n  \"globals\": {\n    \"initial_data\": true,\n    "
  },
  {
    "path": ".flake8",
    "chars": 181,
    "preview": "[flake8]\nmax-line-length = 88\nignore = E501, E203, W503, E402, E231\n# line length, whitespace before ':', line break bef"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 681,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise descriptio"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 560,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? "
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 374,
    "preview": "<!-- add an 'x' in the brackets below -->\n- [] I have added an entry to `CHANGELOG.md`, or an entry is not needed for th"
  },
  {
    "path": ".github/workflows/build_executable.yml",
    "chars": 1333,
    "preview": "name: Build native gdbgui executables with pyinstaller and pex\n\non:\n  pull_request:\n  push:\n    branches:\n      - master"
  },
  {
    "path": ".github/workflows/tests.yml",
    "chars": 2256,
    "preview": "# https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions\n\nname: Tests\n\non:\n  "
  },
  {
    "path": ".gitignore",
    "chars": 185,
    "preview": "dist\n*egg*\nnode_modules\nbuild\nexecutable\n.DS_Store\n*.a.dSYM\ngdbgui_pyinstaller.spec\n*-link\n*-link.c\n*-link.dSYM\n*.pyc\nya"
  },
  {
    "path": ".prettierrc.js",
    "chars": 39,
    "preview": "module.exports = {\n  printWidth: 90,\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 290,
    "preview": "{\n    \"python.formatting.provider\": \"none\",\n    \"[python]\": {\n        \"editor.formatOnSave\": true,\n        \"editor.defau"
  },
  {
    "path": ".vulture_whitelist.py",
    "chars": 1088,
    "preview": "_.sessions  # unused attribute (noxfile.py:7)\n_.reuse_existing_virtualenvs  # unused attribute (noxfile.py:6)\n_.secret_k"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 11029,
    "preview": "# gdbgui release history\n\n## 0.15.3.0\n- Update default python version to 3.13\n\n## 0.15.2.0\n- Update default python versi"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2344,
    "preview": "Thanks for your interest in contributing to gdbgui!\n\nIf your change is small, go ahead and submit a pull request. If it "
  },
  {
    "path": "LICENSE",
    "chars": 35184,
    "preview": "Copyright (C) Chad Smith (Grass Fed Code)\n\n                    GNU GENERAL PUBLIC LICENSE\n                       Version"
  },
  {
    "path": "MANIFEST.in",
    "chars": 864,
    "preview": "include README.md\ninclude LICENSE\ninclude requirements.txt\n\ngraft gdbgui\n# these files are built and must be included in"
  },
  {
    "path": "README.md",
    "chars": 656,
    "preview": "<p align=\"center\">\n<a href=\"http://gdbgui.com\"><img src=\"https://github.com/cs01/gdbgui/raw/master/images/gdbgui_banner."
  },
  {
    "path": "docs/CNAME",
    "chars": 14,
    "preview": "www.gdbgui.com"
  },
  {
    "path": "docs/api.md",
    "chars": 4536,
    "preview": "This is the command line help output of gdbgui.\n\n```\nusage: gdbgui [-h] [-g GDB_CMD] [-p PORT] [--host HOST] [-r]\n      "
  },
  {
    "path": "docs/contact.md",
    "chars": 37,
    "preview": "* Email: chadsmith.software@gmail.com"
  },
  {
    "path": "docs/examples.md",
    "chars": 1505,
    "preview": "\n# Examples\n## Code Examples\nView code examples on [GitHub](https://github.com/cs01/gdbgui/tree/master/examples).\n\n## gd"
  },
  {
    "path": "docs/faq.md",
    "chars": 1469,
    "preview": "## How can I see what commands are being sent to gdb?\nGo to Settings and check the box that says `Print all sent command"
  },
  {
    "path": "docs/gettingstarted.md",
    "chars": 1537,
    "preview": "Before running `gdbgui`, you should compile your program with debug symbols and a lower level of optimization, so code i"
  },
  {
    "path": "docs/guides.md",
    "chars": 7546,
    "preview": "gdb can be used in a plethora of environments. These guides help you get gdb and gdbgui working in specific environments"
  },
  {
    "path": "docs/howitworks.md",
    "chars": 2285,
    "preview": "gdbgui consists of two main parts: the frontend and the backend\n\n## Backend\n\nThe backend is written in Python and consis"
  },
  {
    "path": "docs/index.md",
    "chars": 3023,
    "preview": "<p align=\"center\">\n<a href=\"http://gdbgui.com\"><img src=\"https://github.com/cs01/gdbgui/raw/master/images/gdbgui_banner."
  },
  {
    "path": "docs/installation.md",
    "chars": 3856,
    "preview": "# gdbgui installation\n\nThere are a few ways to install gdbgui on your machine. There is even a way to run gdbgui without"
  },
  {
    "path": "docs/screenshots.md",
    "chars": 4810,
    "preview": "![image](https://github.com/cs01/gdbgui/raw/master/screenshots/gdbgui.png)\n![image](https://github.com/cs01/gdbgui/raw/m"
  },
  {
    "path": "examples/.gitignore",
    "chars": 4,
    "preview": "*.a\n"
  },
  {
    "path": "examples/README.md",
    "chars": 1241,
    "preview": "# Examples\n\n## Overview\n`gdbgui` can debug executables generated from various languages. This folder contains example so"
  },
  {
    "path": "examples/c/debug_segfault.c",
    "chars": 933,
    "preview": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\nint main(void)\n{\n    char* badstring = 0;\n    const char* s "
  },
  {
    "path": "examples/c/hello.c",
    "chars": 1013,
    "preview": "#include <stdio.h>\n#include <string.h>\nvoid say_something(const char *str)\n{\n  printf(\"%s\\n\", str);\n}\n\nstruct mystruct_t"
  },
  {
    "path": "examples/c/input.c",
    "chars": 213,
    "preview": "#include <stdio.h>\n#include <string.h>\n\nint main(int argc, char **argv)\n{\n    char name[20];\n    printf(\"Hello. What's y"
  },
  {
    "path": "examples/c/makefile",
    "chars": 674,
    "preview": "ROOT:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))\n\nhello: hello.c\n\tgcc hello.c -o hello_c.a -std=c99 -g\n\t"
  },
  {
    "path": "examples/c/sleeper.c",
    "chars": 411,
    "preview": "#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n\nint main(int argc, char **argv) {\n  printf(\"entering\\n\");\n  "
  },
  {
    "path": "examples/c/threads.c",
    "chars": 1194,
    "preview": "#include <pthread.h>\n#include <stdio.h>\n\nstatic const int num_increments = 2;\n\n/* this function is run by the second thr"
  },
  {
    "path": "examples/c/tree.c",
    "chars": 1438,
    "preview": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\nstruct Node\n{\n    struct Node* left;\n    struct Node* right;"
  },
  {
    "path": "examples/cpp/hello.cpp",
    "chars": 727,
    "preview": "#include <iostream>\n#include <vector>\n#include <map>\n\nint main(void)\n{\n    std::cout << \"Hello World\" << std::endl;\n\n   "
  },
  {
    "path": "examples/cpp/linked_list.cpp",
    "chars": 843,
    "preview": "#include <iostream>\n\nclass Node{\n\nprivate:\n    Node* next = 0;\n    Node* prev = 0;\n    int value;\n\npublic:\n    Node(int "
  },
  {
    "path": "examples/cpp/makefile",
    "chars": 544,
    "preview": "GDBGUI=../../gdbgui/backend.py\n\nhello: hello.cpp\n\tg++ hello.cpp -o hello_cpp.a -std=c++11 -g\n\t@echo Run with gdbgui: gdb"
  },
  {
    "path": "examples/cpp/sin.cpp",
    "chars": 231,
    "preview": "#include <math.h>       /* sin */\n\nint main ()\n{\n  double angle = 0, result = 0;\n  static const double RAD_TO_DEG = 3.14"
  },
  {
    "path": "examples/cpp/smart_ptr_demo.cpp",
    "chars": 4319,
    "preview": "// A demonstration of unique, smart, weak, and raw pointers in C++11.\n// compile with:\n//  g++ smart_ptr_demo.cpp -std=c"
  },
  {
    "path": "examples/fortran/fortran_array.f90",
    "chars": 472,
    "preview": "program array\n  integer, parameter :: n=3\n  integer :: ii\n  real, dimension(n) :: a, b\n  real, dimension(n,n) :: c\n\n  a "
  },
  {
    "path": "examples/fortran/makefile",
    "chars": 158,
    "preview": "GDBGUI=../../gdbgui/backend.py\n\narray_demo: fortran_array.f90\n\tgfortran fortran_array.f90 -o array_f90.a -g\n\t@echo Run w"
  },
  {
    "path": "examples/golang/hello.go",
    "chars": 265,
    "preview": "package main\nimport \"fmt\"\n\nfunc main() {\n    fmt.Println(\"hello world\")\n    // Create an array of three ints.\n    array "
  },
  {
    "path": "examples/golang/makefile",
    "chars": 147,
    "preview": "GDBGUI=../../gdbgui/backend.py\n\nhello: hello.go\n\tgo build -o hello_go.a -gccgoflags \"-w\" hello.go\n\t@echo Run with gdbgui"
  },
  {
    "path": "examples/rust/.gitignore",
    "chars": 105,
    "preview": "/target/\n**/*.rs.bk\n\n# User-specific stuff:\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/dictionaries\n"
  },
  {
    "path": "examples/rust/Cargo.toml",
    "chars": 106,
    "preview": "[package]\nname = \"hello\"\nversion = \"0.1.0\"\nauthors = [\"Your Name <YourName@example.com>\"]\n\n[dependencies]\n"
  },
  {
    "path": "examples/rust/README.md",
    "chars": 233,
    "preview": "This directory contains a very simple Rust program to demonstrate\nhow to run gdbgui.\n\nRun the shell script `compile_and_"
  },
  {
    "path": "examples/rust/compile_and_debug.sh",
    "chars": 97,
    "preview": "#!/usr/bin/env bash\n\nGDBGUI=../../gdbgui/backend.py\n\ncargo build && $GDBGUI ./target/debug/hello\n"
  },
  {
    "path": "examples/rust/src/main.rs",
    "chars": 1023,
    "preview": "use std::mem;\n\n// This function borrows a slice\nfn analyze_slice(slice: &[i32]) {\n    println!(\"first element of the sli"
  },
  {
    "path": "gdbgui/SSLify.py",
    "chars": 3253,
    "preview": "\"\"\"Module to enable SSL for Flask application. Adapted from\nhttps://github.com/kennethreitz/flask-sslify\n\"\"\"\n\nimport os\n"
  },
  {
    "path": "gdbgui/VERSION.txt",
    "chars": 9,
    "preview": "0.15.3.0\n"
  },
  {
    "path": "gdbgui/__init__.py",
    "chars": 339,
    "preview": "import io\nimport os\nimport sys\n\n_base_dir = getattr(sys, \"_MEIPASS\", os.path.dirname(os.path.realpath(__file__)))\n_versi"
  },
  {
    "path": "gdbgui/__main__.py",
    "chars": 30,
    "preview": "from . import cli\n\ncli.main()\n"
  },
  {
    "path": "gdbgui/cli.py",
    "chars": 9205,
    "preview": "#!/usr/bin/env python\n\n\"\"\"\nA server that provides a graphical user interface to the gnu debugger (gdb).\nhttps://github.c"
  },
  {
    "path": "gdbgui/htmllistformatter.py",
    "chars": 1363,
    "preview": "from pygments.formatters import HtmlFormatter  # type: ignore\n\n\nclass HtmlListFormatter(HtmlFormatter):\n    \"\"\"A custom "
  },
  {
    "path": "gdbgui/py.typed",
    "chars": 158,
    "preview": "# Marker file for PEP 561.  This package uses inline types.\n# https://mypy.readthedocs.io/en/latest/installed_packages.h"
  },
  {
    "path": "gdbgui/server/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "gdbgui/server/app.py",
    "chars": 11141,
    "preview": "import binascii\nimport logging\nimport os\nfrom typing import Dict, List\nimport traceback\nfrom flask import Flask, abort, "
  },
  {
    "path": "gdbgui/server/constants.py",
    "chars": 919,
    "preview": "import os\nimport signal\nimport sys\nfrom pathlib import Path\n\nDEFAULT_GDB_EXECUTABLE = \"gdb\"\nDEFAULT_HOST = \"127.0.0.1\"\nD"
  },
  {
    "path": "gdbgui/server/http_routes.py",
    "chars": 7464,
    "preview": "import json\nimport logging\nimport os\n\nfrom flask import (\n    Blueprint,\n    current_app,\n    jsonify,\n    redirect,\n   "
  },
  {
    "path": "gdbgui/server/http_util.py",
    "chars": 2519,
    "preview": "import binascii\nimport logging\nimport os\nfrom functools import wraps\n\nfrom flask import Response, abort, current_app, js"
  },
  {
    "path": "gdbgui/server/ptylib.py",
    "chars": 2711,
    "preview": "import os\n\nUSING_WINDOWS = os.name == \"nt\"\nif USING_WINDOWS:\n    raise RuntimeError(\n        \"Windows is not supported a"
  },
  {
    "path": "gdbgui/server/server.py",
    "chars": 3203,
    "preview": "import os\nimport socket\nimport webbrowser\n\nfrom .constants import DEFAULT_HOST, DEFAULT_PORT, colorize\n\ntry:\n    from gd"
  },
  {
    "path": "gdbgui/server/sessionmanager.py",
    "chars": 6262,
    "preview": "import datetime\nimport logging\nimport os\nimport signal\nimport traceback\nfrom collections import defaultdict\nfrom typing "
  },
  {
    "path": "gdbgui/src/js/Actions.ts",
    "chars": 9393,
    "preview": "import { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport SourceCode from \"./SourceCode\";\nimport Locals f"
  },
  {
    "path": "gdbgui/src/js/BinaryLoader.tsx",
    "chars": 9873,
    "preview": "import React from \"react\";\nimport constants from \"./constants\";\nimport Actions from \"./Actions\";\nimport Util from \"./Uti"
  },
  {
    "path": "gdbgui/src/js/Breakpoints.tsx",
    "chars": 13848,
    "preview": "import React from \"react\";\nimport { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport Actions from \"./Acti"
  },
  {
    "path": "gdbgui/src/js/ControlButtons.tsx",
    "chars": 4015,
    "preview": "import React from \"react\";\n\nimport Actions from \"./Actions\";\nimport GdbApi from \"./GdbApi\";\nimport { store } from \"stato"
  },
  {
    "path": "gdbgui/src/js/CopyToClipboard.tsx",
    "chars": 1233,
    "preview": "import * as React from \"react\";\nimport ToolTip from \"./ToolTip\";\nimport { store } from \"statorgfc\";\n\ntype Props = {\n  co"
  },
  {
    "path": "gdbgui/src/js/Expressions.tsx",
    "chars": 2827,
    "preview": "import React from \"react\";\nimport { store } from \"statorgfc\";\nimport GdbVariable from \"./GdbVariable\";\nimport constants "
  },
  {
    "path": "gdbgui/src/js/FileOps.tsx",
    "chars": 24138,
    "preview": "import { store } from \"statorgfc\";\nimport GdbApi from \"./GdbApi\";\nimport constants from \"./constants\";\nimport Actions fr"
  },
  {
    "path": "gdbgui/src/js/FileSystem.tsx",
    "chars": 2082,
    "preview": "import React from \"react\";\n\nclass FileSystem extends React.Component {\n  nodecount: any;\n  get_node_jsx(node: any, depth"
  },
  {
    "path": "gdbgui/src/js/FoldersView.tsx",
    "chars": 8132,
    "preview": "import React from \"react\";\nimport { store } from \"statorgfc\";\nimport FileOps from \"./FileOps\";\nimport constants from \"./"
  },
  {
    "path": "gdbgui/src/js/GdbApi.tsx",
    "chars": 16048,
    "preview": "/**\n * An object to manage the websocket connection to the python server that manages gdb,\n * to send various commands t"
  },
  {
    "path": "gdbgui/src/js/GdbMiOutput.tsx",
    "chars": 2322,
    "preview": "/**\n * A component to display, in gory detail, what is\n * returned from gdb's machine interface. This displays the\n * da"
  },
  {
    "path": "gdbgui/src/js/GdbVariable.tsx",
    "chars": 29995,
    "preview": "/**\n * A component to render gdb user variables, and\n * some library functions to interact with gdb. The library\n * func"
  },
  {
    "path": "gdbgui/src/js/GdbguiModal.tsx",
    "chars": 1586,
    "preview": "import React from \"react\";\nimport Actions from \"./Actions\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclass"
  },
  {
    "path": "gdbgui/src/js/GlobalEvents.ts",
    "chars": 2092,
    "preview": "/**\n * Setup global DOM events\n */\n\nimport constants from \"./constants\";\nimport GdbApi from \"./GdbApi\";\nimport { store }"
  },
  {
    "path": "gdbgui/src/js/HoverVar.tsx",
    "chars": 4363,
    "preview": "/**\n * A component to show/hide variable exploration when hovering over a variable\n * in the source code\n */\n\nimport Rea"
  },
  {
    "path": "gdbgui/src/js/InferiorProgramInfo.tsx",
    "chars": 4903,
    "preview": "import React from \"react\";\n\nimport Actions from \"./Actions\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclas"
  },
  {
    "path": "gdbgui/src/js/InitialStoreData.ts",
    "chars": 5839,
    "preview": "/* global initial_data */\n/* global debug */\nimport constants from \"./constants\";\n\n/**\n * The initial store data. Keys c"
  },
  {
    "path": "gdbgui/src/js/Links.tsx",
    "chars": 1808,
    "preview": "import Actions from \"./Actions\";\nimport * as React from \"react\";\nimport CopyToClipboard from \"./CopyToClipboard\";\nimport"
  },
  {
    "path": "gdbgui/src/js/Locals.tsx",
    "chars": 3406,
    "preview": "/**\n * A component to render \"local\" variables, as well as a few static methods to\n * assist in their creation and delet"
  },
  {
    "path": "gdbgui/src/js/Memory.tsx",
    "chars": 9682,
    "preview": "/**\n * The Memory component allows the user to view\n * data stored at memory locations. It has some\n * static methods us"
  },
  {
    "path": "gdbgui/src/js/MemoryLink.tsx",
    "chars": 794,
    "preview": "import * as React from \"react\";\nimport Memory from \"./Memory\";\n\ntype OwnProps = {\n  addr: string;\n  style?: React.CSSPro"
  },
  {
    "path": "gdbgui/src/js/MiddleLeft.tsx",
    "chars": 2429,
    "preview": "/**\n * The middle left div will be rendered with this content\n */\n\nimport React from \"react\";\nimport SourceCode from \"./"
  },
  {
    "path": "gdbgui/src/js/ReactTable.tsx",
    "chars": 2112,
    "preview": "import React from \"react\";\n\nclass TableRow extends React.Component {\n  className: any;\n  get_tds() {\n    let tds = [];\n "
  },
  {
    "path": "gdbgui/src/js/Registers.tsx",
    "chars": 6155,
    "preview": "/**\n * A component to display, fetch, and store register\n */\n\nimport React from \"react\";\nimport { store } from \"statorgf"
  },
  {
    "path": "gdbgui/src/js/RightSidebar.tsx",
    "chars": 10156,
    "preview": "/**\n * A component to show/hide variable exploration when hovering over a variable\n * in the source code\n */\n\nimport Rea"
  },
  {
    "path": "gdbgui/src/js/Settings.tsx",
    "chars": 4991,
    "preview": "import { store } from \"statorgfc\";\nimport Actions from \"./Actions\";\nimport ToolTip from \"./ToolTip\";\nimport React from \""
  },
  {
    "path": "gdbgui/src/js/SourceCode.tsx",
    "chars": 16304,
    "preview": "/**\n * A component to render source code, assembly, and break points\n */\n\nimport { store } from \"statorgfc\";\nimport Reac"
  },
  {
    "path": "gdbgui/src/js/SourceCodeHeading.tsx",
    "chars": 1547,
    "preview": "import React from \"react\";\nimport constants from \"./constants\";\nimport { store } from \"statorgfc\";\nimport { FileLink } f"
  },
  {
    "path": "gdbgui/src/js/SourceFileAutocomplete.tsx",
    "chars": 4084,
    "preview": "import { store } from \"statorgfc\";\nimport constants from \"./constants\";\nimport Actions from \"./Actions\";\nimport Util fro"
  },
  {
    "path": "gdbgui/src/js/StatusBar.tsx",
    "chars": 458,
    "preview": "import React from \"react\";\nimport Util from \"./Util\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\n/**\n * Comp"
  },
  {
    "path": "gdbgui/src/js/Terminals.tsx",
    "chars": 5709,
    "preview": "import React from \"react\";\nimport GdbApi from \"./GdbApi\";\nimport { Terminal } from \"xterm\";\nimport { FitAddon } from \"xt"
  },
  {
    "path": "gdbgui/src/js/Threads.tsx",
    "chars": 7689,
    "preview": "import React from \"react\";\nimport ReactTable from \"./ReactTable\";\nimport { store } from \"statorgfc\";\nimport GdbApi from "
  },
  {
    "path": "gdbgui/src/js/ToolTip.tsx",
    "chars": 2199,
    "preview": "import React from \"react\";\nimport { store } from \"statorgfc\";\n\nclass ToolTip extends React.Component {\n  timeout: any;\n "
  },
  {
    "path": "gdbgui/src/js/ToolTipTourguide.tsx",
    "chars": 5719,
    "preview": "import React from \"react\";\nimport Util from \"./Util\";\nimport { store } from \"statorgfc\";\n\ntype State = any;\n\nclass ToolT"
  },
  {
    "path": "gdbgui/src/js/TopBar.tsx",
    "chars": 14524,
    "preview": "import React from \"react\";\n\nimport { store } from \"statorgfc\";\nimport BinaryLoader from \"./BinaryLoader\";\nimport Control"
  },
  {
    "path": "gdbgui/src/js/Tree.ts",
    "chars": 12326,
    "preview": "// a widget to visualize a tree view of a variable with children\n// utilizes the amazing http://visjs.org library\n\n/* gl"
  },
  {
    "path": "gdbgui/src/js/Util.ts",
    "chars": 3609,
    "preview": "import { store } from \"statorgfc\";\n\n/**\n * Some general utility methods\n */\nconst Util = {\n  persist_value_for_key: func"
  },
  {
    "path": "gdbgui/src/js/constants.ts",
    "chars": 3930,
    "preview": "let constants = {\n  ENTER_BUTTON_NUM: 13,\n  TAB_BUTTON_NUM: 9,\n  LEFT_BUTTON_NUM: 37,\n  UP_BUTTON_NUM: 38,\n  RIGHT_BUTTO"
  },
  {
    "path": "gdbgui/src/js/dashboard.tsx",
    "chars": 8810,
    "preview": "import ReactDOM from \"react-dom\";\nimport React, { useState } from \"react\";\nimport \"../../static/css/tailwind.css\";\n\ntype"
  },
  {
    "path": "gdbgui/src/js/gdbgui.tsx",
    "chars": 6897,
    "preview": "/**\n * This is the entrypoint to the frontend applicaiton.\n *\n * store (global state) is managed in a single location, a"
  },
  {
    "path": "gdbgui/src/js/processFeatures.ts",
    "chars": 637,
    "preview": "// https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Support-Commands.html#GDB_002fMI-Support-Commands\n\nimport { stor"
  },
  {
    "path": "gdbgui/src/js/process_gdb_response.tsx",
    "chars": 13030,
    "preview": "/**\n * This is the main callback when receiving a response from gdb.\n * This callback generally updates the store, which"
  },
  {
    "path": "gdbgui/src/js/register_descriptions.ts",
    "chars": 11404,
    "preview": "export default {\n  // x86_64\n  rax: \"register a extended (64-bit)\",\n  rbx: \"register b extended (64-bit)\",\n  rcx: \"regis"
  },
  {
    "path": "gdbgui/src/js/tests/Util.jest.ts",
    "chars": 1224,
    "preview": "import Util from \"../Util\";\n\n/* eslint-env jest */\n\ntest(\"parses spaces\", () => {\n  const fn = Util.string_to_array_safe"
  },
  {
    "path": "gdbgui/src/js/types.d.ts",
    "chars": 124,
    "preview": "declare module \"statorgfc\" {\n  export let store: {\n    get(key: string): any;\n    set(key: string, value: any): any;\n  }"
  },
  {
    "path": "gdbgui/static/css/gdbgui.css",
    "chars": 8638,
    "preview": "@import \"tailwindcss/base\";\n@import \"tailwindcss/components\";\n@import \"tailwindcss/utilities\";\n\n/* styling for all html "
  },
  {
    "path": "gdbgui/static/css/splitjs-gdbgui.css",
    "chars": 1083,
    "preview": "/* splitjs is so unopinionated, it doesn't work without specific css classes (float: left) when splitting into two side-"
  },
  {
    "path": "gdbgui/static/css/tailwind.css",
    "chars": 258,
    "preview": "@import \"tailwindcss/base\";\n@import \"tailwindcss/components\";\n@import \"tailwindcss/utilities\";\n\nbutton:focus {\n  /* For "
  },
  {
    "path": "gdbgui/static/vendor/css/animate.css",
    "chars": 23848,
    "preview": "@charset \"UTF-8\";\n\n/*!\n * animate.css -http://daneden.me/animate\n * Version - 3.5.2\n * Licensed under the MIT license - "
  },
  {
    "path": "gdbgui/static/vendor/css/gdbgui_awesomeplete.css",
    "chars": 2169,
    "preview": "/* This is mostly from the vendor, with a few overrides for gdbgui */\n\n.awesomplete [hidden] {\n    display: none;\n}\n\n.aw"
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/emacs.css",
    "chars": 4059,
    "preview": ".emacs .hll { background-color: #ffffcc }\n.emacs .c { color: #008800; font-style: italic } /* Comment */\n.emacs .err { b"
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/light.css",
    "chars": 4828,
    "preview": "/* gdbgui-specific stuff */\n.light {\n    background-color: white;\n    color: black;\n}\n\n/* when hovering, set background "
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/monokai.css",
    "chars": 4848,
    "preview": "/* gdbgui-specific stuff*/\n.monokai {\n    background-color: #333;\n    color: grey;\n}\n\n/* when hovering, set background c"
  },
  {
    "path": "gdbgui/static/vendor/css/pygments/vim.css",
    "chars": 4009,
    "preview": ".vim .hll { background-color: #222222 }\n.vim .c { color: #000080 } /* Comment */\n.vim .err { color: #cccccc; border: 1px"
  },
  {
    "path": "gdbgui/static/vendor/js/splitjs.min-1.2.0.js",
    "chars": 5261,
    "preview": "/*! Split.js - v1.2.0 */\n\"use strict\";(function(){var a=this,b=a.attachEvent&&!a[d],c=a.document,d=\"addEventListener\",e="
  },
  {
    "path": "gdbgui/templates/dashboard.html",
    "chars": 730,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\" class=\"text-gray-900 antialiased leading-tight font-sans\">\n  <head>\n    <meta charset=\"u"
  },
  {
    "path": "gdbgui/templates/gdbgui.html",
    "chars": 1755,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-w"
  },
  {
    "path": "jest.config.js",
    "chars": 185,
    "preview": "module.exports = {\n    \"preset\": 'ts-jest',\n    \"verbose\": true,\n    \"testMatch\": [__dirname  + '/gdbgui/src/js/tests/**"
  },
  {
    "path": "make_executable.py",
    "chars": 2865,
    "preview": "#!/usr/bin/env python\n\n\"\"\"\nBuild an executable of gdbgui for the current platform\n\"\"\"\n\n\nimport subprocess\nfrom sys impor"
  },
  {
    "path": "mkdocs.yml",
    "chars": 780,
    "preview": "site_name: gdbgui\nsite_description: A browser-based frontend to gdb (gnu debugger)\n\ntheme:\n  name: \"material\"\nrepo_name:"
  },
  {
    "path": "noxfile.py",
    "chars": 5904,
    "preview": "import subprocess\nfrom pathlib import Path\nfrom sys import platform\n\nimport hashlib\nimport nox  # type: ignore\nimport gl"
  },
  {
    "path": "package.json",
    "chars": 1497,
    "preview": "{\n  \"name\": \"gdbgui\",\n  \"version\": \"0.1.0\",\n  \"license\": \"GPL-3.0\",\n  \"scripts\": {\n    \"start\": \"cross-env NODE_OPTIONS="
  },
  {
    "path": "postcss.config.js",
    "chars": 140,
    "preview": "const tailwindcss = require(\"tailwindcss\");\nmodule.exports = {\n  plugins: [tailwindcss(\"./tailwind.config.js\"), require("
  },
  {
    "path": "requirements.in",
    "chars": 106,
    "preview": "Flask-SocketIO>5.3, <6\nFlask-Compress>1.10, <1.11\npygdbmi>=0.10.0.2, <0.11\nPygments>=2.2.0, <3.0\neventlet\n"
  },
  {
    "path": "requirements.txt",
    "chars": 1027,
    "preview": "#\n# This file is autogenerated by pip-compile with Python 3.14\n# by the following command:\n#\n#    pip-compile\n#\nbidict=="
  },
  {
    "path": "setup.py",
    "chars": 2203,
    "preview": "#!/usr/bin/env python\n\nimport os\nimport distutils.text_file  # type: ignore\n\nUSING_WINDOWS = os.name == \"nt\"\nif USING_WI"
  },
  {
    "path": "tailwind.config.js",
    "chars": 145,
    "preview": "module.exports = {\n  purge: [\"./gdbgui/src/js/**\", \"./gdbgui/templates/*.html\"],\n  theme: {\n    extend: {}\n  },\n  varian"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/test_backend.py",
    "chars": 1553,
    "preview": "from flask_socketio import send, SocketIO  # type: ignore\nimport pytest  # type: ignore\n\nfrom gdbgui.server.server impor"
  },
  {
    "path": "tests/test_cli.py",
    "chars": 1533,
    "preview": "import sys\nfrom typing import List\nfrom unittest import mock\n\nimport gdbgui\nimport pytest  # type: ignore\n\n\ndef run_gdbg"
  },
  {
    "path": "tests/test_ptylib.py",
    "chars": 224,
    "preview": "from gdbgui.server import ptylib\n\nimport os\n\n\ndef test_pty():\n    pty = ptylib.Pty()\n    assert pty.name\n    os.write(pt"
  },
  {
    "path": "tests/test_sessionmanager.py",
    "chars": 390,
    "preview": "from gdbgui.server import sessionmanager\n\n\ndef test_SessionManager():\n    manager = sessionmanager.SessionManager()\n    "
  },
  {
    "path": "tsconfig.json",
    "chars": 528,
    "preview": "{\n  \"compilerOptions\": {\n    \"allowJs\": true,\n    \"downlevelIteration\": true,\n    \"forceConsistentCasingInFileNames\": tr"
  },
  {
    "path": "tslint.json",
    "chars": 350,
    "preview": "{\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true,\n    \"jquery\": true\n  },\n  \"extends\": [\"tslint-config-prettier\"],\n  \"g"
  },
  {
    "path": "webpack.config.js",
    "chars": 901,
    "preview": "const path = require(\"path\");\nconst ForkTsCheckerWebpackPlugin = require(\"fork-ts-checker-webpack-plugin\");\n\nmodule.expo"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the cs01/gdbgui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 143 files (526.7 KB), approximately 141.3k tokens, and a symbol index with 463 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!