diff --git a/.envrc b/.envrc deleted file mode 100644 index 3550a30..0000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 79f4893..cc65ced 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,16 +9,19 @@ on: jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11"] steps: - - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 with: - nix_path: nixpkgs=channel:nixos-unstable - - uses: cachix/cachix-action@v12 - with: - name: fzakaria - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - run: nix develop --command make lint - - run: nix develop --command make test - - run: nix build --print-build-logs - - run: nix run . -- --help \ No newline at end of file + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install .[dev] + - run: make lint + - run: make test + - run: sqlelf --help \ No newline at end of file diff --git a/.gitignore b/.gitignore index 26cf45e..a54462a 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,13 @@ dist/ result examples/**/exe examples/**/*.so +venv/ +temp/ +# Unit test / coverage reports +.coverage +.tox +.coverage.* +.pytest_cache/ +nosetests.xml +coverage.xml +htmlcov diff --git a/Makefile b/Makefile index 32d3292..4b4d754 100644 --- a/Makefile +++ b/Makefile @@ -17,16 +17,12 @@ show: ## Show the current environment. fmt: ## Format code using black & isort. isort sqlelf/ black sqlelf/ - nixpkgs-fmt . .PHONY: lint lint: ## Run pep8, black, mypy linters. flake8 sqlelf/ black --check sqlelf/ -# TODO(fzakaria): without pythonpath it picks up the wrong python -# and then does not find the venv for the imports - pyright --pythonpath $(shell which python) - nixpkgs-fmt --check . + pyright .PHONY: test test: ## Run pytest primarily. diff --git a/README.md b/README.md index 937dfee..1d61221 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # sqlelf -![example workflow](https://github.com/fzakaria/sqlelf/actions/workflows/main.yml/badge.svg) -[![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org) +![build workflow](https://github.com/fzakaria/sqlelf/actions/workflows/main.yml/badge.svg) > Explore ELF objects through the power of SQL @@ -67,10 +66,11 @@ erDiagram ``` ## Installation -This repository can easily be installed, you simply need to have [Nix or NixOS](https://nixos.org) installed. - ```console -❯ nix run github:fzakaria/sqlelf /usr/bin/python3 -- \ +❯ python3 -m venv venv +❯ source venv/bin/activate +❯ pip install . +❯ sqlelf /usr/bin/python3 -- \ --sql "select mnemonic, COUNT(*) from elf_instructions GROUP BY mnemonic ORDER BY 2 DESC LIMIT 3" mov|223497 @@ -78,12 +78,6 @@ call|56209 jmp|48213 ``` -Note: I publish artifacts to [cachix](https://cachix.org/) that you can use to develop faster. - -```console -> cachix use fzakaria -``` - ## Usage ```console ❯ sqlelf --help @@ -102,6 +96,7 @@ options: ``` Note: You may provide directories for `FILE`. Avoid giving too many binaries though since they must all be parsed at startup. + ## Tour You simply have to fire up `sqlelf` and give it a list of binaries or directories and start exploring ELF via SQL. @@ -249,14 +244,10 @@ WHERE ## Development -You must have [Nix](https://nixos.org) installed for development. - -This package uses [poetry2nix](https://github.com/nix-community/poetry2nix) to easily setup a development environment. +You may want to install the package in _editable mode_ as well to make development easier ```console -❯ nix develop -$ sqlelf --help -usage: sqlelf [-h] [-s SQL] FILE [FILE ...] +> pip install --editable ".[dev]" ``` A helping `Makefile` is provided to run all the _linters_ and _formatters_. diff --git a/flake.lock b/flake.lock deleted file mode 100644 index b696520..0000000 --- a/flake.lock +++ /dev/null @@ -1,107 +0,0 @@ -{ - "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1692799911, - "narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nix-github-actions": { - "inputs": { - "nixpkgs": [ - "poetry2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1688870561, - "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", - "owner": "nix-community", - "repo": "nix-github-actions", - "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nix-github-actions", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1693341273, - "narHash": "sha256-wrsPjsIx2767909MPGhSIOmkpGELM9eufqLQOPxmZQg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "2ab91c8d65c00fd22a441c69bbf1bc9b420d5ea1", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-23.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "poetry2nix": { - "inputs": { - "flake-utils": [ - "flake-utils" - ], - "nix-github-actions": "nix-github-actions", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1693051011, - "narHash": "sha256-HNbuVCS/Fnl1YZOjBk9/MlIem+wM8fvIzTH0CVQrLSQ=", - "owner": "nix-community", - "repo": "poetry2nix", - "rev": "5b3a5151cf212021ff8d424f215fb030e4ff2837", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "poetry2nix", - "type": "github" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "poetry2nix": "poetry2nix" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 39c91ac..0000000 --- a/flake.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - description = "Explore ELF objects through the power of SQL"; - inputs = { - flake-utils.url = "github:numtide/flake-utils"; - nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; - poetry2nix = { - url = "github:nix-community/poetry2nix"; - inputs = { - nixpkgs.follows = "nixpkgs"; - flake-utils.follows = "flake-utils"; - }; - }; - }; - - outputs = { self, nixpkgs, flake-utils, poetry2nix }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { - inherit system; - overlays = [ poetry2nix.overlay (import ./nix/overlay.nix) ]; - }; - in - { - packages = { - sqlelf = pkgs.sqlelf; - default = pkgs.sqlelf; - }; - - devShell = pkgs.sqlelf-env.env.overrideAttrs - (oldAttrs: { buildInputs = with pkgs; [ poetry nixpkgs-fmt ]; }); - }); -} diff --git a/nix/derivation.nix b/nix/derivation.nix deleted file mode 100644 index 13e2406..0000000 --- a/nix/derivation.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ poetry2nix, poetryOverrides }: -poetry2nix.mkPoetryApplication { - projectDir = ../.; - overrides = poetry2nix.overrides.withDefaults poetryOverrides; -} diff --git a/nix/lief.nix b/nix/lief.nix deleted file mode 100644 index e0e6908..0000000 --- a/nix/lief.nix +++ /dev/null @@ -1,44 +0,0 @@ -# This is an unreleased version of Lief that fixes a bug when generates GNU notes -# https://github.com/lief-project/LIEF/commit/3414ded8cdcbd9705f7871c66c212b15cd74ea69 -# Nixpkgs derivation was updated to change how lief was built since it no longer has setup.py -# in the root of the directory. -# For now, we copy the derivation until it's merged into nixpkgs we are tracking. -# https://github.com/NixOS/nixpkgs/pull/251414 -{ fetchFromGitHub, python, stdenv, cmake, ninja }: -let - pyEnv = python.withPackages (ps: [ ps.setuptools ps.tomli ps.pip ps.setuptools ]); -in -stdenv.mkDerivation rec { - pname = "lief"; - version = "0.14.0-3414ded"; - src = fetchFromGitHub { - owner = "lief-project"; - repo = "LIEF"; - rev = "3414ded8cdcbd9705f7871c66c212b15cd74ea69"; - sha256 = "sha256-GJTj4w8HhAiC2bQAjEIqPw9feaOHL4fmAfLACioW0Q0="; - }; - outputs = [ "out" "py" ]; - - nativeBuildInputs = [ - cmake - ninja - ]; - - # Not a propagatedBuildInput because only the $py output needs it; $out is - # just the library itself (e.g. C/C++ headers). - buildInputs = [ - python - ]; - - postBuild = '' - pushd /build/source/api/python - ${pyEnv.interpreter} setup.py build --parallel=$NIX_BUILD_CORES - popd - ''; - - postInstall = '' - pushd /build/source/api/python - ${pyEnv.interpreter} setup.py install --skip-build --root=/ --prefix=$py - popd - ''; -} diff --git a/nix/overlay.nix b/nix/overlay.nix deleted file mode 100644 index f31bd34..0000000 --- a/nix/overlay.nix +++ /dev/null @@ -1,40 +0,0 @@ -self: super: { - - sqlelf = self.callPackage ./derivation.nix { }; - - sqlelf-env = self.poetry2nix.mkPoetryEnv { - projectDir = ../.; - overrides = self.poetry2nix.overrides.withDefaults self.poetryOverrides; - editablePackageSources = { sqlelf = ./sqlelf; }; - }; - - sqlite-3430 = self.sqlite.overrideAttrs (oldAttrs: rec { - version = "3.43.0"; - src = self.fetchurl { - url = "https://sqlite.org/2023/sqlite-autoconf-3430000.tar.gz"; - sha256 = "sha256-SQCNvzr8BNTtyOz8NOTq0ZaXMDQpPJl62tL2PwF2KuE="; - }; - }); - - - lief-3414ded = self.callPackage ./lief.nix { python = self.python3; }; - - poetryOverrides = self: super: { - lief = super.toPythonModule super.pkgs.lief-3414ded.py; - - sh = super.sh.overridePythonAttrs (old: { - buildInputs = (old.buildInputs or [ ]) ++ [ super.poetry ]; - }); - - apsw = super.apsw.overridePythonAttrs (old: rec { - version = "3.43.1.0"; - src = super.pkgs.fetchFromGitHub { - owner = "rogerbinns"; - repo = "apsw"; - rev = "refs/tags/${version}"; - sha256 = "sha256-x+bSft37DgF2tXXCL6ac86g1+mj/wJeDLoCSiVSXedA="; - }; - buildInputs = (old.buildInputs or [ ]) ++ [ super.pkgs.sqlite-3430 ]; - }); - }; -} diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 41fe5b4..0000000 --- a/poetry.lock +++ /dev/null @@ -1,469 +0,0 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. - -[[package]] -name = "apsw" -version = "3.43.1.0" -description = "Another Python SQLite Wrapper" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "apsw-3.43.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bb37e563cac333b276c9374d67f629319fa52b122d779e0da3f104a96c608149"}, - {file = "apsw-3.43.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e17d33f189cc7054bee7b8958d105946458c6721391152cbe21501319fa5f8b0"}, - {file = "apsw-3.43.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c92dae70e33719907091f8bd789d9b4a17d93782a88961b16bb52d260d9b3f30"}, - {file = "apsw-3.43.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:962180d60eedf37f5d880d35ca4c6517a7a83c087a84f7e96b7703f859c89196"}, - {file = "apsw-3.43.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f86dd863b38164b22316445f131d923a9b362ac885b937ac21ac6f4931c8287d"}, - {file = "apsw-3.43.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcb4a386d44dce8e3fda996a9e8f712a7d83a48e742ac9b790389983a9c5a5b7"}, - {file = "apsw-3.43.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:53ba8459f68ab8a480693462606c445ec45885833c3d559dc6f7fbf9cda69c89"}, - {file = "apsw-3.43.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d39f2d1aa25cd8ad040b43faf71ace9560c3e5e9532445e78a6713366b43f9a2"}, - {file = "apsw-3.43.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d05931e7e9757faa224f9bed4f97761bb2f106f208b359ca3bff2116fa24e41a"}, - {file = "apsw-3.43.1.0-cp310-cp310-win32.whl", hash = "sha256:ea6590b36506200aae48934cff9c23cd544b81af6e2fdc920c9e8c42ca289880"}, - {file = "apsw-3.43.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:10e64d6c80c630b775e86e849e9c56a52df8cf36fd13a8d4a58eb4ae77422cc9"}, - {file = "apsw-3.43.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5fbd5369a17e9f34bc9c5a28fb6712df4147ce92ae3885d9dda37ae5b74f0627"}, - {file = "apsw-3.43.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:00704fc3ccd2336f01559ffa05dd8aefad8b9d476322e0164b7e6d98636e63e9"}, - {file = "apsw-3.43.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:09c9a8fc8e452fea6a96a5af6a5d8813435dd07f98402315c07492fd7bc4dcb9"}, - {file = "apsw-3.43.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab9f963106f41a5eeb48084a993acc7196a2e698c2c45ac540fac8aa54995e15"}, - {file = "apsw-3.43.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a4795840f6300173cdd45785cff35cc9d7294b660b57a1fc30aa65e245dd4d6"}, - {file = "apsw-3.43.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57e32195f2fd9decfb8520c7826a35e6a486547a49624eed9a471f45ce544fce"}, - {file = "apsw-3.43.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b496a42f1899e6113ceede4f633f186e3665d918fb0aad8e41e638b45c4fb7cd"}, - {file = "apsw-3.43.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0df9557e8cbbee826a8d0ada2f4bc69df2b9c74ba7be39b493a054617ff18741"}, - {file = "apsw-3.43.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:663999a3998b38a855e4e61d11f051289f1a687416e3109503efea8c2e611b7c"}, - {file = "apsw-3.43.1.0-cp311-cp311-win32.whl", hash = "sha256:900e0ce793bd5771a4908c997384895a7dbf7c4dba8cf1f91d460dbeeb715fa4"}, - {file = "apsw-3.43.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:9505d9b5ee6fbd8bcc27fe27795cfb17a9d8634b8f7c346dafb4e092374e6cc0"}, - {file = "apsw-3.43.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5bd6bfb59f95bdf07fdb4365e3d6ccc94be310b583ad60cddebd892527973dff"}, - {file = "apsw-3.43.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ea2151b6e836637b8a8425a27978880916a87fb48e3833acfeabdfa25caabaf1"}, - {file = "apsw-3.43.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c88b680cd311b1a1ceba3f8e82ab97ededb4046a738822120a0aa65583abb058"}, - {file = "apsw-3.43.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ae19356528befc07a99789a0a5c58d24cf71c1e80623a2d8660525833070df"}, - {file = "apsw-3.43.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d614af7d9827c868b5ed61b74b41e33fd9805b19820b54a7d4892f071ce5509e"}, - {file = "apsw-3.43.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06c3831a8142c1e3458bd4e450c9243558f6c1c3224b322d8664c4e7762e23c0"}, - {file = "apsw-3.43.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:853ef200e07894697aaaf5baa03c0bfd46c2bb988e09f5664d87d6504a07fa8e"}, - {file = "apsw-3.43.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36e4e250340d247c95da439cfc67855e7412c806080031d75d37f0a1362a9d73"}, - {file = "apsw-3.43.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f23a22d54fd92c57d5e3421103652ae4322c27be48da97266760278a1a0408c3"}, - {file = "apsw-3.43.1.0-cp312-cp312-win32.whl", hash = "sha256:d5033fcb9781b484752d63395efce9b0f278e5b7c6c7c002da1c7f15eabe90c7"}, - {file = "apsw-3.43.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:4fb2ef4762c3aba99f6794606b7c8b5c35b8d7719c51a76bbbda4ac3fefff79c"}, - {file = "apsw-3.43.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:46aaf0c10b758c2a213a87bdb5c83dd9bd218b5fb5866eb3206b2cd1344a905b"}, - {file = "apsw-3.43.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a84d01994d57ab8526688dfb99c24067707442a02177002d0212295b35c4288"}, - {file = "apsw-3.43.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:55965ee1a6eb008c96b1da1bfd8485407964df600b4a3744f89dd87a9321894c"}, - {file = "apsw-3.43.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63d7f4a9a6b37eb66ebc3cd977265d1c9fe929e7b208e90498eb3112029a0c4f"}, - {file = "apsw-3.43.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ec3a678c60e63bb9e4fd870ee065a63ac13ea01ef5b9aa224dc4eac7ba377d9"}, - {file = "apsw-3.43.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:99e513c743b8d2c20b1914a9bc8df8c9b22dfbfa82cb384958bf76ac856e7771"}, - {file = "apsw-3.43.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5a06ed873bf7f5f80c022e288e26930ba57c90910875d1f416af5a643a40f09e"}, - {file = "apsw-3.43.1.0-cp38-cp38-win32.whl", hash = "sha256:3ef1c25ac0e51d9b62cdc980bbc09addcfd785b881655ac5db1cec3bafaa8b74"}, - {file = "apsw-3.43.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b6a7c401f0684c146086d4592b0e06c6850b1174142e4829984f96f771ed39a8"}, - {file = "apsw-3.43.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:979999820225991f1d85d8212bd7074220acbb561663e79f91ba270e019deb50"}, - {file = "apsw-3.43.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ac8947db1bb92e820839729ce64468da3eca6ef9e9896409ec22c23ed9aa1f8"}, - {file = "apsw-3.43.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:45d0ec300e31a789aa90fa94825c50b84f1a9f390f29d3081592732425d34c52"}, - {file = "apsw-3.43.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0513079eade996db380dda5d8da266dee0da7eda53ed2e815335466d1654f23e"}, - {file = "apsw-3.43.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f4e37f906c4b9cf7667af8d36fb4c3112f4b0702dbc09a4d272ed29ec004fb"}, - {file = "apsw-3.43.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:786a5110e2b57013104be4f8064d67a94131e469f16601afbfe3cef2f92add19"}, - {file = "apsw-3.43.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c4d574c5e36523259a63b453747fd7c13e7bc8124752482b8a16bd6617debf35"}, - {file = "apsw-3.43.1.0-cp39-cp39-win32.whl", hash = "sha256:7cb5ca320b91e6b2e4a043f045d2e2f1e3c4d54b7f20980409d52fa4d2ad3324"}, - {file = "apsw-3.43.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:ca75a53efd01f6ca4725d45ffecf34a2cc1e461cf72cdbb2f4675ec6b76f05ca"}, - {file = "apsw-3.43.1.0.tar.gz", hash = "sha256:7e2cbbb407b6d1146bbd966de5843688b4deaa2cb07d98690689a42d00363cdd"}, -] - -[[package]] -name = "black" -version = "23.9.1" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"}, - {file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"}, - {file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"}, - {file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"}, - {file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"}, - {file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"}, - {file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"}, - {file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"}, - {file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"}, - {file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"}, - {file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"}, - {file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"}, - {file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"}, - {file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"}, - {file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"}, - {file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "capstone" -version = "5.0.1" -description = "Capstone disassembly engine" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "capstone-5.0.1-py3-none-macosx_10_9_universal2.whl", hash = "sha256:740a70624d3f258cf8503898dbfd968052c008ddd4fc4ab938c7046c8828c294"}, - {file = "capstone-5.0.1-py3-none-manylinux1_i686.manylinux_2_5_i686.whl", hash = "sha256:3f34a949699c298e88d7c9a576a2fd7685dba658a9c432bce826eeb88676cf24"}, - {file = "capstone-5.0.1-py3-none-manylinux1_i686.whl", hash = "sha256:08f16c2782e54d05c95f1d40e1ae0e58e4a57d6a6c3192f8c5ff61476f4130de"}, - {file = "capstone-5.0.1-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ea8d0be06d2faa39545937fe88db239fd62227915f9744d8990439011c479f05"}, - {file = "capstone-5.0.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:04223a4e5c2374f21da59c5c5a5b90471bfcef5cb938e7b32de68579cf863b7a"}, - {file = "capstone-5.0.1-py3-none-win32.whl", hash = "sha256:4356bdee55639c4448d025dc9d8a3b6c07f2b188c62b88df3d554a84e2cd89af"}, - {file = "capstone-5.0.1-py3-none-win_amd64.whl", hash = "sha256:1bfa5c81e6880caf41a31946cd6d2d069c048bcc22edf121254b501a048de675"}, - {file = "capstone-5.0.1.tar.gz", hash = "sha256:740afacc29861db591316beefe30df382c4da08dcb0345a0d10f0cac4f8b1ee2"}, -] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "exceptiongroup" -version = "1.1.3" -description = "Backport of PEP 654 (exception groups)" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "flake8" -version = "6.1.0" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "isort" -version = "5.12.0" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - -[[package]] -name = "lief" -version = "0.13.2" -description = "Library to instrument executable formats" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "lief-0.13.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:0390cfaaf0e9aed46bebf26f00f34852768f76bc7f90abf7ceb384566200e5f5"}, - {file = "lief-0.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5581bf0072c1e7a9ea2fb2e2252b8582016e8b298804b5461e552b402c9cd4e9"}, - {file = "lief-0.13.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:dbbf2fb3d7807e815f345c77e287da162e081100f059ec03005995befc295d7f"}, - {file = "lief-0.13.2-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:d344d37334c2b488dc02f04cb13c22cd61aa065eeb9bca7424588e0c8c23bdfb"}, - {file = "lief-0.13.2-cp310-cp310-win32.whl", hash = "sha256:bc041b28b94139843a33c014e355822a9276b35f3c5ae10d82da56bf572f8222"}, - {file = "lief-0.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:01d4075bbc3541e9dd3ef008045fa1eb128294a0c5b0c1f69ce60d8948d248c7"}, - {file = "lief-0.13.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:6570dacebe107ad60c2ba0968d1a865d316009d43cc85af3719d3eeb0911abf3"}, - {file = "lief-0.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7ce2e3f7c791efba327c2bb3499dbef81e682027109045a9bae696c62e2aeeb0"}, - {file = "lief-0.13.2-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:11ab900e0644b6735ecdef2bbd04439b4866a527650fc054470c195d6cfe2917"}, - {file = "lief-0.13.2-cp311-cp311-manylinux_2_24_x86_64.whl", hash = "sha256:042ad2105a136b11a7494b9af8178468e8cb32b8fa2a0a55cb659a5605aeb069"}, - {file = "lief-0.13.2-cp311-cp311-win32.whl", hash = "sha256:1ce289b6ab3cf4be654270007e8a2c0d2e42116180418c29d3ce83762955de63"}, - {file = "lief-0.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:eccb248ffb598e410fd2ef7c1f171a3cde57a40c9bb8c4fa15d8e7b90eb4eb2d"}, - {file = "lief-0.13.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:95731cadedd6ffc5fb48c147fcefe004624e436b75e8ee9fb2dbf2ae5f084342"}, - {file = "lief-0.13.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8da75df0ea472557fcc37a27ba583bad5a8f3a256c186600d00a6dd0a57f718a"}, - {file = "lief-0.13.2-cp38-cp38-manylinux_2_24_x86_64.whl", hash = "sha256:b99092f02c13f580c2d00b504af224b7e60e7c98a791e72ae8519f530b7687bb"}, - {file = "lief-0.13.2-cp38-cp38-win32.whl", hash = "sha256:03db0138e4dbbdfa8bba74de312b0cebb30f504e44f38a9c8918b84022da340b"}, - {file = "lief-0.13.2-cp38-cp38-win_amd64.whl", hash = "sha256:36c5bea3f8460dee3ebb75d35949f445638ec85d2871f31e293c47fb4a0a5af7"}, - {file = "lief-0.13.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:eca8ecbcae1ad851ed7cf1e22ec8accd74f2267fa7375194559fb917523d8a92"}, - {file = "lief-0.13.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8703cb5308b4828563badc6885ff07a3926ec3403d1caa3aa75f24fe9cbcf84"}, - {file = "lief-0.13.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c60f2f79e7d0d1f18dec7dcdb4d4f35e6b126ac29e2f2f056d28ec50599d868a"}, - {file = "lief-0.13.2-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:e0f84a7443b7f1b02666fd16a9aa57f5d9027e60ba2885e0d76db8426d689707"}, - {file = "lief-0.13.2-cp39-cp39-win32.whl", hash = "sha256:3f8f251de874929d9c9e94a35891621ab8c059149f8a1c24e543fd9cf0c2a31c"}, - {file = "lief-0.13.2-cp39-cp39-win_amd64.whl", hash = "sha256:2bbe294385e629aa7206b2f39f0ca34e3948605a8db50b22091603053889a759"}, -] - -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "nodeenv" -version = "1.8.0" -description = "Node.js virtual environment builder" -category = "dev" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" -files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, -] - -[package.dependencies] -setuptools = "*" - -[[package]] -name = "packaging" -version = "23.1" -description = "Core utilities for Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, -] - -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, -] - -[[package]] -name = "platformdirs" -version = "3.10.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, -] - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] - -[[package]] -name = "pluggy" -version = "1.3.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pycodestyle" -version = "2.11.0" -description = "Python style guide checker" -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"}, - {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"}, -] - -[[package]] -name = "pyflakes" -version = "3.1.0" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, -] - -[[package]] -name = "pyright" -version = "1.1.325" -description = "Command line wrapper for pyright" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyright-1.1.325-py3-none-any.whl", hash = "sha256:8f3ab88ba4843f053ab5b5c886d676161aba6f446776bfb57cc0434ed4d88672"}, - {file = "pyright-1.1.325.tar.gz", hash = "sha256:879a3f66944ffd59d3facd54872fed814830fed64daf3e8eb71b146ddd83bb67"}, -] - -[package.dependencies] -nodeenv = ">=1.6.0" - -[package.extras] -all = ["twine (>=3.4.1)"] -dev = ["twine (>=3.4.1)"] - -[[package]] -name = "pytest" -version = "7.4.2" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "setuptools" -version = "68.2.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, - {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "sh" -version = "2.0.6" -description = "Python subprocess replacement" -category = "main" -optional = false -python-versions = ">=3.8.1,<4.0" -files = [ - {file = "sh-2.0.6-py3-none-any.whl", hash = "sha256:ced8f2e081a858b66a46ace3703dec243779abbd5a1887ba7e3c34f34da70cd2"}, - {file = "sh-2.0.6.tar.gz", hash = "sha256:9b2998f313f201c777e2c0061f0b1367497097ef13388595be147e2a00bf7ba1"}, -] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, -] - -[metadata] -lock-version = "2.0" -python-versions = ">=3.10,<4.0" -content-hash = "7405102db2d5dde4fc96cc9ee8da0a34a2fd3027e3659dd9f0cb5b348d8fd5e4" diff --git a/pyproject.toml b/pyproject.toml index f637323..3d7ea4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,38 +1,36 @@ -[tool.poetry] +[build-system] +requires = ["setuptools", "setuptools-scm"] +build-backend = "setuptools.build_meta" + +[project] name = "sqlelf" version = "0.0.1" -authors = ["Farid Zakaria "] +authors = [{ name = "Farid Zakaria", email = "farid.m.zakaria@gmail.com" }] readme = "README.md" description = "Explore ELF objects through the power of SQL" -license = "LICENSE" - -[tool.poetry.dependencies] -python = ">=3.10,<4.0" -capstone = "^5.0.1" -# These two packages are being versioned using Nix -# you will want to refer to ./nix/overlay.nix to see the exact versions -# you cannot trust the versions in the poetry.lock file -lief = ">=0.13.2" -apsw = "^3.43.1.0" -# TODO(fzakaria): Would love to specify this as an exact version -# but I was getting weird failures with `nix build` -# ERROR: Could not find a version that satisfies the requirement setuptools<61.0.0,>=60.0.0 (from sqlelf) (from versions: none) -# ERROR: No matching distribution found for setuptools<61.0.0,>=60.0.0 -setuptools = "*" -sh = "^2.0.6" - -[tool.poetry.group.dev.dependencies] -black = "^23.7.0" -isort = "^5.12.0" -flake8 = "^6.1.0" -pyright = "^1.1.325" -pytest = "^7.4.0" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" - -[tool.poetry.scripts] +license = { file = "LICENSE" } +requires-python = ">=3.10,<4.0" + +dependencies = [ + "capstone >= 5.0.1", + "lief >=0.13.2", + "apsw >= 3.43.1.0", + "sh >= 2.0.6", +] + +[project.optional-dependencies] +dev = [ + "black >= 23.7.0", + "isort >= 5.12.0", + "flake8 >= 6.1.0", + "pyright >= 1.1.325", + "pytest >= 7.4.0", +] + +[tool.setuptools] +packages = ["sqlelf"] + +[project.scripts] sqlelf = "sqlelf.cli:start" [tool.isort] diff --git a/sqlelf/__init__.py b/sqlelf/__init__.py index e69de29..b4f3730 100644 --- a/sqlelf/__init__.py +++ b/sqlelf/__init__.py @@ -0,0 +1,4 @@ +import apsw.bestpractice + +# forward sqlite logs to logging module +apsw.bestpractice.apply(apsw.bestpractice.recommended) diff --git a/sqlelf/cli.py b/sqlelf/cli.py index 8b70f44..c5cd880 100644 --- a/sqlelf/cli.py +++ b/sqlelf/cli.py @@ -4,13 +4,9 @@ import sys from functools import reduce -import apsw -import apsw.bestpractice -import apsw.shell +import lief -from sqlelf import ldd -from sqlelf.elf import dynamic, header, instruction, section, strings, symbol -from sqlelf.elf.binary import Binary +from sqlelf import sql as api_sql def start(args=sys.argv[1:], stdin=sys.stdin): @@ -54,45 +50,16 @@ def start(args=sys.argv[1:], stdin=sys.stdin): ), ) # Filter the list of filenames to those that are ELF files only - filenames = list( - filter(lambda f: os.path.isfile(f) and Binary.is_elf(f), filenames) - ) + filenames = [f for f in filenames if os.path.isfile(f) and lief.is_elf(f)] # If none of the inputs are valid files, simply return if len(filenames) == 0: sys.exit("No valid ELF files were provided") - binaries: list[Binary] = [Binary(filename) for filename in filenames] - - # If the recursive option is specidied, load the shared libraries - # the binary would load as well. - if args.recursive: - shared_libraries = [ldd.libraries(binary).values() for binary in binaries] - # We want to readlink on the libraries to resolve symlinks such as libm -> libc - # also make this is a set in the case that multiple binaries use the same - shared_libraries = set( - [ - os.path.realpath(library) - for sub_list in shared_libraries - for library in sub_list - ] - ) - binaries = binaries + [Binary(library) for library in shared_libraries] - - # forward sqlite logs to logging module - apsw.bestpractice.apply(apsw.bestpractice.recommended) - - # Now we create the connection - connection = apsw.Connection(":memory:") - header.register(connection, binaries) - section.register(connection, binaries) - symbol.register(connection, binaries) - dynamic.register(connection, binaries) - strings.register(connection, binaries) - instruction.register(connection, binaries) + binaries: list[lief.Binary] = [lief.parse(filename) for filename in filenames] - shell = apsw.shell.Shell(db=connection, stdin=stdin) - shell.command_prompt(["sqlelf> "]) + sql_engine = api_sql.make_sql_engine(binaries, recursive=args.recursive) + shell = sql_engine.shell(stdin=stdin) if args.sql: for sql in args.sql: diff --git a/sqlelf/elf/binary.py b/sqlelf/elf/binary.py deleted file mode 100644 index d04fc5a..0000000 --- a/sqlelf/elf/binary.py +++ /dev/null @@ -1,33 +0,0 @@ -# pyright: strict -from typing import TYPE_CHECKING, Any - -import lief - -# Let's make sure type checking works for this proxy class -# https://stackoverflow.com/questions/71365594/how-to-make-a-proxy-object-with-typing-as-underlying-object-in-python -if TYPE_CHECKING: - base = lief.ELF.Binary -else: - base = object - - -class Binary(base): - """Proxy the lief.Binary object to add a path attribute. - - As of https://github.com/lief-project/LIEF/issues/839 the name - attribute in lief.Binary was removed. Rather than passing around - a tuple let's create a nice proxy class. - """ - - def __init__(self, path: str): - self.path = path - self.__binary = lief.parse(path) - - if not TYPE_CHECKING: - - def __getattr__(self, attr: str) -> Any: - return getattr(self.__binary, attr) - - @staticmethod - def is_elf(path: str): - return lief.is_elf(path) diff --git a/sqlelf/elf/dynamic.py b/sqlelf/elf/dynamic.py index 5c8c0b4..d933b59 100644 --- a/sqlelf/elf/dynamic.py +++ b/sqlelf/elf/dynamic.py @@ -5,29 +5,24 @@ import apsw import apsw.ext - -from sqlelf.elf.binary import Binary +import lief # This is effectively the .dynamic section but it is elevated as a table here # since it is widely used and can benefit from simpler table access. -def elf_dynamic_entries(binaries: list[Binary]): +def elf_dynamic_entries(binaries: list[lief.Binary]): def generator() -> Iterator[dict[str, Any]]: for binary in binaries: # super important that these accessors are pulled out of the tight loop # as they can be costly - binary_path = binary.path - for entry in binary.dynamic_entries: - yield { - "path": binary_path, - "tag": entry.tag.__name__, - "value": entry.value, - } + binary_name = binary.name + for entry in binary.dynamic_entries: # pyright: ignore + yield {"path": binary_name, "tag": entry.tag.name, "value": entry.value} return generator -def register(connection: apsw.Connection, binaries: list[Binary]): +def register(connection: apsw.Connection, binaries: list[lief.Binary]): generator = elf_dynamic_entries(binaries) # setup columns and access by providing an example of the first entry returned generator.columns, generator.column_access = apsw.ext.get_column_names( diff --git a/sqlelf/elf/header.py b/sqlelf/elf/header.py index 89d62ca..e4e7b51 100644 --- a/sqlelf/elf/header.py +++ b/sqlelf/elf/header.py @@ -2,25 +2,24 @@ import apsw import apsw.ext +import lief -from sqlelf.elf.binary import Binary - -def elf_headers(binaries: list[Binary]): +def elf_headers(binaries: list[lief.Binary]): def generator() -> Iterator[dict[str, Any]]: for binary in binaries: yield { - "path": binary.path, - "type": binary.header.file_type.__name__, - "machine": binary.header.machine_type.__name__, - "version": binary.header.identity_version.__name__, + "path": binary.name, + "type": binary.header.file_type.name, + "machine": binary.header.machine_type.name, + "version": binary.header.identity_version.name, "entry": binary.header.entrypoint, } return generator -def register(connection: apsw.Connection, binaries: list[Binary]): +def register(connection: apsw.Connection, binaries: list[lief.Binary]): generator = elf_headers(binaries) # setup columns and access by providing an example of the first entry returned generator.columns, generator.column_access = apsw.ext.get_column_names( diff --git a/sqlelf/elf/instruction.py b/sqlelf/elf/instruction.py index fa6580f..7637e17 100644 --- a/sqlelf/elf/instruction.py +++ b/sqlelf/elf/instruction.py @@ -10,15 +10,13 @@ import capstone # pyright: ignore import lief -from sqlelf.elf.binary import Binary - -def elf_instructions(binaries: list[Binary]): +def elf_instructions(binaries: list[lief.Binary]): def generator() -> Iterator[dict[str, Any]]: for binary in binaries: # super important that these accessors are pulled out of the tight loop # as they can be costly - binary_path = binary.path + binary_name = binary.name for section in binary.sections: if section.has(lief.ELF.SECTION_FLAGS.EXECINSTR): @@ -36,7 +34,7 @@ def generator() -> Iterator[dict[str, Any]]: data, section.virtual_address ): yield { - "path": binary_path, + "path": binary_name, "section": section_name, "mnemonic": mnemonic, "address": address, @@ -46,19 +44,19 @@ def generator() -> Iterator[dict[str, Any]]: return generator -def mode(binary: Binary) -> int: +def mode(binary: lief.Binary) -> int: if binary.header.identity_class == lief.ELF.ELF_CLASS.CLASS64: return capstone.CS_MODE_64 - raise Exception(f"Unknown mode for {binary.path}") + raise Exception(f"Unknown mode for {binary.name}") -def arch(binary: Binary) -> int: +def arch(binary: lief.Binary) -> int: if binary.header.machine_type == lief.ELF.ARCH.x86_64: return capstone.CS_ARCH_X86 - raise Exception(f"Unknown machine type for {binary.path}") + raise Exception(f"Unknown machine type for {binary.name}") -def register(connection: apsw.Connection, binaries: list[Binary]): +def register(connection: apsw.Connection, binaries: list[lief.Binary]): generator = elf_instructions(binaries) # setup columns and access by providing an example of the first entry returned generator.columns, generator.column_access = apsw.ext.get_column_names( diff --git a/sqlelf/elf/section.py b/sqlelf/elf/section.py index a40b499..969440c 100644 --- a/sqlelf/elf/section.py +++ b/sqlelf/elf/section.py @@ -5,23 +5,22 @@ import apsw import apsw.ext +import lief -from sqlelf.elf.binary import Binary - -def elf_sections(binaries: list[Binary]): +def elf_sections(binaries: list[lief.Binary]): def generator() -> Iterator[dict[str, Any]]: for binary in binaries: # super important that these accessors are pulled out of the tight loop # as they can be costly - binary_path = binary.path + binary_name = binary.name for section in binary.sections: yield { - "path": binary_path, + "path": binary_name, "name": section.name, "offset": section.offset, "size": section.size, - "type": section.type.__name__, + "type": section.type.name, "content": bytes(section.content), } @@ -34,7 +33,7 @@ def section_name(name: str | None) -> str | None: return name -def register(connection: apsw.Connection, binaries: list[Binary]): +def register(connection: apsw.Connection, binaries: list[lief.Binary]): generator = elf_sections(binaries) # setup columns and access by providing an example of the first entry returned generator.columns, generator.column_access = apsw.ext.get_column_names( diff --git a/sqlelf/elf/strings.py b/sqlelf/elf/strings.py index db076b0..456ead3 100644 --- a/sqlelf/elf/strings.py +++ b/sqlelf/elf/strings.py @@ -7,10 +7,8 @@ import apsw.ext import lief -from sqlelf.elf.binary import Binary - -def elf_strings(binaries: list[Binary]): +def elf_strings(binaries: list[lief.Binary]): def generator() -> Iterator[dict[str, Any]]: for binary in binaries: strtabs = [ @@ -20,19 +18,19 @@ def generator() -> Iterator[dict[str, Any]]: ] # super important that these accessors are pulled out of the tight loop # as they can be costly - binary_path = binary.path + binary_name = binary.name for strtab in strtabs: # The first byte is always the null byte in the STRTAB # Python also treats the final null in the string by creating # an empty item so we chop it off. # https://stackoverflow.com/a/18970869 for string in str(strtab.content[1:-1], "utf-8").split("\x00"): - yield {"path": binary_path, "section": strtab.name, "value": string} + yield {"path": binary_name, "section": strtab.name, "value": string} return generator -def register(connection: apsw.Connection, binaries: list[Binary]): +def register(connection: apsw.Connection, binaries: list[lief.Binary]): generator = elf_strings(binaries) # setup columns and access by providing an example of the first entry returned generator.columns, generator.column_access = apsw.ext.get_column_names( diff --git a/sqlelf/elf/symbol.py b/sqlelf/elf/symbol.py index 55987c7..968b039 100644 --- a/sqlelf/elf/symbol.py +++ b/sqlelf/elf/symbol.py @@ -6,17 +6,15 @@ import apsw import apsw.ext import lief - -from sqlelf.elf.binary import Binary from sqlelf.elf.section import section_name as elf_section_name -def elf_symbols(binaries: list[Binary]): +def elf_symbols(binaries: list[lief.Binary]): def generator() -> Iterator[dict[str, Any]]: for binary in binaries: # super important that these accessors are pulled out of the tight loop # as they can be costly - binary_path = binary.path + binary_name = binary.name for symbol in symbols(binary): # The section index can be special numbers like 65521 or 65522 # that refer to special sections so they can't be indexed @@ -27,10 +25,10 @@ def generator() -> Iterator[dict[str, Any]]: if shndx == symbol.shndx ), None, - ) # pyright: ignore (https://github.com/lief-project/LIEF/issues/965) + ) yield { - "path": binary_path, + "path": binary_name, "name": symbol.name, "demangled_name": symbol.demangled_name, # A bit of detailed explanation here to explain these values. @@ -52,14 +50,14 @@ def generator() -> Iterator[dict[str, Any]]: if symbol.symbol_version and symbol.symbol_version.symbol_version_auxiliary else None, - "type": symbol.type.__name__, + "type": symbol.type.name, "value": symbol.value, } return generator -def symbols(binary: Binary) -> Iterator[lief.ELF.Symbol]: +def symbols(binary: lief.Binary) -> Iterator[lief.ELF.Symbol]: """Use heuristic to either get static symbols or dynamic symbol table The static symbol table is a superset of the dynamic symbol table. @@ -72,13 +70,13 @@ def symbols(binary: Binary) -> Iterator[lief.ELF.Symbol]: A bad actor is free to strip arbitrarily from the static symbol table and it would affect this method. """ - static_symbols = binary.static_symbols + static_symbols = binary.static_symbols # pyright: ignore - missing from pyi if len(static_symbols) > 0: return static_symbols - return binary.dynamic_symbols + return binary.dynamic_symbols # pyright: ignore - missing from pyi -def register(connection: apsw.Connection, binaries: list[Binary]): +def register(connection: apsw.Connection, binaries: list[lief.Binary]): generator = elf_symbols(binaries) # setup columns and access by providing an example of the first entry returned generator.columns, generator.column_access = apsw.ext.get_column_names( diff --git a/sqlelf/ldd.py b/sqlelf/ldd.py index 3b606d3..0db6832 100644 --- a/sqlelf/ldd.py +++ b/sqlelf/ldd.py @@ -2,15 +2,14 @@ from collections import OrderedDict from typing import Dict +import lief import sh # pyright: ignore -from sqlelf.elf.binary import Binary - -def libraries(binary: Binary) -> Dict[str, str]: +def libraries(binary: lief.Binary) -> Dict[str, str]: """Use the interpreter in a binary to determine the path of each linked library""" interpreter = sh.Command(binary.interpreter) # pyright: ignore - resolution = interpreter("--list", binary.path) + resolution = interpreter("--list", binary.name) result = OrderedDict() # TODO: Figure out why `--list` and `ldd` produce different outcomes # specifically for the interpreter. diff --git a/sqlelf/sql.py b/sqlelf/sql.py new file mode 100644 index 0000000..9aa8979 --- /dev/null +++ b/sqlelf/sql.py @@ -0,0 +1,59 @@ +import os +import sys +from dataclasses import dataclass +from typing import Any, Iterator + +import apsw +import apsw.shell +import lief + +from sqlelf import ldd +from sqlelf.elf import dynamic, header, instruction, section, strings, symbol + + +@dataclass +class SQLEngine: + connection: apsw.Connection + + def shell(self, stdin=sys.stdin) -> apsw.shell.Shell: + shell = apsw.shell.Shell(db=self.connection, stdin=stdin) + shell.command_prompt(["sqlelf> "]) + return shell + + def execute_raw(self, sql: str) -> apsw.Cursor: + return self.connection.execute(sql) + + def execute(self, sql: str) -> Iterator[dict[str, Any]]: + cursor = self.execute_raw(sql) + description = cursor.getdescription() + column_names = [n for n, _ in description] + for row in cursor: + yield dict(zip(column_names, row)) + + +def make_sql_engine(binaries: list[lief.Binary], recursive=False) -> SQLEngine: + connection = apsw.Connection(":memory:") + + if recursive: + # We want to load all the shared libraries needed by each binary + # so we can analyze them as well + shared_libraries = [ldd.libraries(binary).values() for binary in binaries] + # We want to readlink on the libraries to resolve + # symlinks such as libm -> libc + # also make this is a set in the case that multiple binaries use the same + shared_libraries = set( + [ + os.path.realpath(library) + for sub_list in shared_libraries + for library in sub_list + ] + ) + binaries = binaries + [lief.parse(library) for library in shared_libraries] + + header.register(connection, binaries) + section.register(connection, binaries) + symbol.register(connection, binaries) + dynamic.register(connection, binaries) + strings.register(connection, binaries) + instruction.register(connection, binaries) + return SQLEngine(connection) diff --git a/tests/test_ldd.py b/tests/test_ldd.py index 19c2637..6fa3242 100644 --- a/tests/test_ldd.py +++ b/tests/test_ldd.py @@ -1,17 +1,21 @@ from sqlelf import ldd -from sqlelf.elf.binary import Binary +import lief from unittest.mock import patch + def test_simple_binary_real(): - binary = Binary("/bin/ls") + binary = lief.parse("/bin/ls") result = ldd.libraries(binary) assert len(result) > 0 @patch("sh.Command") def test_simple_binary_mocked(Command): - binary = Binary("/bin/ls") - Command(binary.interpreter).return_value = """ + binary = lief.parse("/bin/ls") + interpreter = binary.interpreter # pyright: ignore + Command( + interpreter + ).return_value = """ linux-vdso.so.1 (0x00007ffc5d8ff000) /lib/x86_64-linux-gnu/libnss_cache.so.2 (0x00007f6995d92000) libselinux.so.1 => not found @@ -22,8 +26,14 @@ def test_simple_binary_mocked(Command): result = ldd.libraries(binary) assert len(result) == 4 assert result["fake.so.6"] == "/some-path/fake.so.6" - assert result["/lib64/ld-linux-x86-64.so.2"] == "/nix/store/46m4xx889wlhsdj72j38fnlyyvvvvbyb-glibc-2.37-8/lib64/ld-linux-x86-64.so.2" - assert result["libc.so.6"] == "/nix/store/46m4xx889wlhsdj72j38fnlyyvvvvbyb-glibc-2.37-8/lib/libc.so.6" + assert ( + result["/lib64/ld-linux-x86-64.so.2"] + == "/nix/store/46m4xx889wlhsdj72j38fnlyyvvvvbyb-glibc-2.37-8/lib64/ld-linux-x86-64.so.2" + ) + assert ( + result["libc.so.6"] + == "/nix/store/46m4xx889wlhsdj72j38fnlyyvvvvbyb-glibc-2.37-8/lib/libc.so.6" + ) # TODO(fzakaria):better handling for not found # kind of a weird one since this should never happen though - assert result["libselinux.so.1"] == "not" \ No newline at end of file + assert result["libselinux.so.1"] == "not" diff --git a/tests/test_sql.py b/tests/test_sql.py new file mode 100644 index 0000000..bcfdba8 --- /dev/null +++ b/tests/test_sql.py @@ -0,0 +1,13 @@ +from sqlelf import sql +import lief + + +def test_simple_select_header(): + engine = sql.make_sql_engine([lief.parse("/bin/ls")]) + result = list(engine.execute("SELECT * FROM elf_headers LIMIT 1")) + assert len(result) == 1 + assert "path" in result[0] + assert "type" in result[0] + assert "version" in result[0] + assert "machine" in result[0] + assert "entry" in result[0]