{"id":16333081,"url":"https://github.com/fzakaria/sqlelf","last_synced_at":"2025-04-05T13:06:03.671Z","repository":{"id":138609211,"uuid":"612368074","full_name":"fzakaria/sqlelf","owner":"fzakaria","description":"Explore ELF objects through the power of SQL","archived":false,"fork":false,"pushed_at":"2024-08-04T00:58:33.000Z","size":358,"stargazers_count":251,"open_issues_count":1,"forks_count":8,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-10-11T23:34:24.117Z","etag":null,"topics":["elf","sql","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fzakaria.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"fzakaria"}},"created_at":"2023-03-10T19:40:05.000Z","updated_at":"2024-10-10T07:17:42.000Z","dependencies_parsed_at":"2024-02-19T04:30:21.659Z","dependency_job_id":"01c66112-c2d1-4767-8e35-d756b934114e","html_url":"https://github.com/fzakaria/sqlelf","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fsqlelf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fsqlelf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fsqlelf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzakaria%2Fsqlelf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fzakaria","download_url":"https://codeload.github.com/fzakaria/sqlelf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247339155,"owners_count":20923014,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elf","sql","sqlite"],"created_at":"2024-10-10T23:34:15.528Z","updated_at":"2025-04-05T13:06:03.653Z","avatar_url":"https://github.com/fzakaria.png","language":"Python","funding_links":["https://github.com/sponsors/fzakaria"],"categories":[],"sub_categories":[],"readme":"# sqlelf\n\n[![PyPI - Version](https://img.shields.io/pypi/v/sqlelf.svg)](https://pypi.org/project/sqlelf)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sqlelf.svg)](https://pypi.org/project/sqlelf)\n![build workflow](https://github.com/fzakaria/sqlelf/actions/workflows/main.yml/badge.svg)\n\n\u003e Explore ELF objects through the power of SQL\n\nA tool that utilizes SQLite's virtual table functionality to allow you to explore Linux ELF objects through SQL.\n\nTraditionally exploring an ELF file was limited to tools such as `objdump` or `readelf`. While these tools are full featured in their parsing capability, the output format and ability to ask exploratory questions is limited.\n\n`SQL` is the _lingua franca_ for asking questions in a declarative manner.\nLet's enhance our ability to introspect binaries!\n\n```mermaid\n---\ntitle: ELF Schema\n---\nerDiagram\n    ELF_HEADERS ||--o{ ELF_SECTIONS : contains\n    ELF_HEADERS {\n        string path\n        int type\n        int version\n        int machine\n        int entry\n    }\n    ELF_SECTIONS {\n        string path\n        string name\n        int offset\n        int size\n        int type\n        blob content\n    }\n    ELF_HEADERS ||--o{ ELF_SYMBOLS : contains\n    ELF_SECTIONS ||--o{ ELF_SYMBOLS : defined\n    ELF_SYMBOLS {\n        string path\n        string name\n        string demangled_name\n        bool imported\n        bool exported\n        int section\n        int size\n    }\n    ELF_HEADERS ||--o{ ELF_DYNAMIC_ENTRIES : defined\n    ELF_DYNAMIC_ENTRIES {\n        string path\n        string tag\n        string value\n    }\n    ELF_SECTIONS ||--o{ ELF_INSTRUCTIONS : contains\n    ELF_INSTRUCTIONS {\n        string path\n        string section\n        string mnemonic\n        string address\n        string operands\n    }\n    ELF_SECTIONS ||--o{ ELF_STRINGS : contains\n    ELF_STRINGS {\n        string path\n        string section\n        string value\n    }\n    ELF_HEADERS ||--o{ ELF_VERSION_REQUIREMENTS : contains\n    ELF_VERSION_REQUIREMENTS {\n        string path\n        string file\n        string name\n    }\n    ELF_HEADERS ||--o{ ELF_VERSION_DEFINITIONS : contains\n    ELF_VERSION_DEFINITIONS {\n        string path\n        string name\n        int flags\n    }\n```\n\n## Installation\n\n```console\n❯ pip install sqlelf\n❯ sqlelf /usr/bin/python3 -- \\\n--sql \"select mnemonic, COUNT(*) from elf_instructions GROUP BY mnemonic ORDER BY 2 DESC LIMIT 3\"\n\nmov|223497\ncall|56209\njmp|48213\n```\n\n### Nix\n\nYou can also run this via [Nix](https://nixos.org/)!\n```console\n❯ nix run github:fzakaria/sqlelf -- --help\nusage: sqlelf [-h] [-s SQL] [--recursive | --no-recursive] [--cache-flag CACHE_FLAG] FILE [FILE ...]\n```\n\n## Usage\n\n```console\n❯ sqlelf --help\nusage: sqlelf [-h] FILE [FILE ...]\n\nAnalyze ELF files with the power of SQL\n\npositional arguments:\n  FILE        The ELF file to analyze\n\noptions:\n  -h, --help            show this help message and exit\n  -s SQL, --sql SQL     Potential SQL to execute. Omitting this enters the REPL.\n  --recursive, --no-recursive\n                        Load all shared libraries needed by each file using ldd\n```\n\nNote: You may provide directories for `FILE`. Avoid giving too many binaries though since they must all be parsed at startup.\n\n## Tour\n\nYou simply have to fire up `sqlelf` and give it a list of binaries or directories and start exploring ELF via SQL.\n\nSimple demo showing a simple `SELECT` :\n\n```console\n❯ sqlelf /usr/bin/ruby --sql \"select * from elf_headers\"\n/usr/bin/ruby|DYNAMIC|x86_64|CURRENT|4400\n```\n\n```console\n❯ sqlelf /usr/bin/ruby /bin/ls\nSQLite version 3.40.1 (APSW 3.40.0.0)\nEnter \".help\" for instructions\nEnter SQL statements terminated with a \";\"\nsqlite\u003e .header ON\nsqlite\u003e select * from elf_headers;\npath|type|machine|version|entry\n/usr/bin/ruby|3|62|1|4400\n/bin/ls|3|62|1|25040\n```\n\nA more intricate demo showing an `INNER JOIN`, `WHERE` and `GROUP BY` across two tables which each represent different portions of the ELF format.\n\n```console\nSQLite version 3.40.1 (APSW 3.40.0.0)\nEnter \".help\" for instructions\nEnter SQL statements terminated with a \";\"\nsqlite\u003e .header ON\nsqlite\u003e SELECT elf_headers.path, COUNT(*) as num_sections\n    ..\u003e FROM elf_headers\n    ..\u003e INNER JOIN elf_sections ON elf_headers.path = elf_sections.path\n    ..\u003e WHERE elf_headers.type = 3\n    ..\u003e GROUP BY elf_headers.path;\npath|num_sections\n/bin/ls|31\n/usr/bin/pnmarith|27\n/usr/bin/ruby|28\n```\n\nYou can provide _multiple SQL_ statements to the CLI. This is useful if you want to invoke many of the special _dot_ commands. You can use `.help` to see the list of possible commands or refer to the [apsw shell documentation](https://rogerbinns.github.io/apsw/shell.html).\n\nFor instance, to have _sqelf_ emit JSON you can do the following:\n\n```console\n❯ sqlelf /usr/bin/ruby --sql \".mode json\" --sql \"select path,name from elf_sections LIMIT 3;\"\n{ \"path\": \"\\/usr\\/bin\\/ruby\", \"name\": \"\"},\n{ \"path\": \"\\/usr\\/bin\\/ruby\", \"name\": \".interp\"},\n{ \"path\": \"\\/usr\\/bin\\/ruby\", \"name\": \".note.gnu.property\"},\n```\n\n`sqlelf` will store the data from the ELF file into in-memory SQLite database. This allows you to run multiple queries against the same file(s) without having to reparse them and is much more efficient than iterating the ELF structures. This comes at the cost of startup time.\n\nYou can however _dump_ the sqlite database to a file on disk and then load it back up later. This is useful if you want to run many queries against the same file(s) and don't want to pay the startup cost each time.\n\n```console\n❯ sqlelf /nix/store/gjr9ylm023rl9di484g1wxcd1jp84xxv-nix-2.8.1/bin/nix \\\n    --sql \".dump /tmp/nix.sqlite\"\n❯ file /tmp/nix-backup.sqlite\n/tmp/nix-backup.sqlite: SQLite 3.x database, last written using SQLite version 3043001, writer version 2,\n    read version 2, file counter 3, database pages 14069, cookie 0x2, schema 4, UTF-8, version-valid-for 3\n```\n\n### Queries\n\n\u003cdetails\u003e\n\u003csummary\u003eList all symbol resolutions (match import \u0026 export)\u003c/summary\u003e\n\n```console\n❯ sqlelf /usr/bin/ruby --sql \"SELECT caller.path as 'caller.path',\n       callee.path as 'calee.path',\n       caller.name,\n       caller.demangled_name\nFROM ELF_SYMBOLS caller\nINNER JOIN ELF_SYMBOLS callee\nON\ncaller.name = callee.name AND\ncaller.path != callee.path AND\ncaller.imported = TRUE AND\ncallee.exported = TRUE\nLIMIT 25;\"\n┌──────────────────────────────────────────┬──────────────────────────────────────────┬──────────────────────┬──────────────────────┐\n│               caller.path                │                calee.path                │         name         │    demangled_name    │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ ruby_run_node        │ ruby_run_node        │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ ruby_init            │ ruby_init            │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ ruby_options         │ ruby_options         │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ ruby_sysinit         │ ruby_sysinit         │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libc.so.6          │ __stack_chk_fail     │ __stack_chk_fail     │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ ruby_init_stack      │ ruby_init_stack      │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libc.so.6          │ setlocale            │ setlocale            │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libc.so.6          │ __libc_start_main    │ __libc_start_main    │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libc.so.6          │ __libc_start_main    │ __libc_start_main    │\n│ /usr/bin/ruby                            │ /lib/x86_64-linux-gnu/libc.so.6          │ __cxa_finalize       │ __cxa_finalize       │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ initgroups           │ initgroups           │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libm.so.6          │ log10                │ log10                │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ chmod                │ chmod                │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libgmp.so.10       │ __gmpz_mul           │ __gmpz_mul           │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libm.so.6          │ lgamma_r             │ lgamma_r             │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ symlink              │ symlink              │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ mprotect             │ mprotect             │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ pipe2                │ pipe2                │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ seteuid              │ seteuid              │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ chdir                │ chdir                │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ fileno               │ fileno               │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ dup2                 │ dup2                 │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ pthread_cond_destroy │ pthread_cond_destroy │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libc.so.6          │ pthread_cond_destroy │ pthread_cond_destroy │\n│ /lib/x86_64-linux-gnu/libruby-3.1.so.3.1 │ /lib/x86_64-linux-gnu/libm.so.6          │ atan2                │ atan2                │\n└──────────────────────────────────────────┴──────────────────────────────────────────┴──────────────────────┴──────────────────────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eFind symbols that are exported by more than one library\u003c/summary\u003e\n\n```console\n❯ sqlelf ./examples/shadowed-symbols/exe --recursive --sql \"\nSELECT name, version, count(*) as symbol_count, GROUP_CONCAT(path, ':') as libraries\nFROM elf_symbols\nWHERE exported = TRUE\nGROUP BY name, version\nHAVING count(*) \u003e= 2;\"\n┌──────┬────────┬───────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐\n│ name │ versio │ symbol_co │                                                                       libraries                                                                        │\n│      │   n    │    unt    │                                                                                                                                                        │\n├──────┼────────┼───────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤\n│ foo  │ NULL   │ 2         │ /usr/local/google/home/fmzakari/code/github.com/fzakaria/sqlelf/examples/shadowed-                                                                     │\n│      │        │           │ symbols/x/libx.so:/usr/local/google/home/fmzakari/code/github.com/fzakaria/sqlelf/examples/shadowed-symbols/x/libx2.so                                 │\n└──────┴────────┴───────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e List contained symbols, i.e. a symbol fully within the bounds of another\u003c/summary\u003e\n\n```console\nsqlelf ./examples/nested-symbols/exe --sql \"\nSELECT outer_symbol.path, \n    outer_symbol.name AS outer_symbol_name, \n    inner_symbol.name AS inner_symbol_name\nFROM \n    elf_symbols AS outer_symbol, \n    elf_symbols AS inner_symbol\nWHERE\n    inner_symbol.section = '.text' AND\n    outer_symbol.section = '.text' AND\n    inner_symbol.path = outer_symbol.path AND\n    inner_symbol.value \u003e outer_symbol.value AND\n    (inner_symbol.value + inner_symbol.size) \u003c (outer_symbol.value + outer_symbol.size) AND\n    inner_symbol.name != outer_symbol.name LIMIT 5;\"\n┌──────────────────────────────────┬───────────────────┬───────────────────┐\n│               path               │ outer_symbol_name │ inner_symbol_name │\n│ ./examples/nested-symbols/nested │ outer_function    │ inner_symbol      │\n└──────────────────────────────────┴───────────────────┴───────────────────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eDetermine Python extension version\u003c/summary\u003e\n\nYou will need to edit the SQL below to have the _module name_.\nFor instance, the below assumes the module name is `extension` from the\n[pypa/python-manylinux-demo](https://github.com/pypa/python-manylinux-demo).\n\n```console\n❯ sqlelf pypa/python-manylinux-demo/build/lib.linux-x86_64-cpython-311/pymanylinuxdemo/extension.cpython-311-x86_64-linux-gnu.so \\\n\u003e --sql \"SELECT\n            CASE name\n                WHEN 'initextension' THEN 2\n                WHEN 'PyInit_extension' THEN 3\n                WHEN '_cffi_pypyinit_extension' THEN 2\n                ELSE -1\n            END AS python_version\n        FROM elf_symbols\n        WHERE name IN ('initextension', 'PyInit_extension', '_cffi_pypyinit_extension')\n              AND exported = TRUE\n              AND type = 'FUNC'\n        LIMIT 1\n        \"\n┌────────────────┐\n│ python_version │\n│ 3              │\n└────────────────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eDetermine the NEEDED entries for a program\u003c/summary\u003e\n\n_This may be improved in the future but for now there is a little knowledge of the\npolymorphic nature of the dynamic entries needed_.\n\n```console\n❯ sqlelf extension.cpython-311-x86_64-linux-gnu.so \\\n\u003e --sql \"SELECT elf_strings.path, elf_strings.value\nFROM elf_dynamic_entries\nINNER JOIN elf_strings ON elf_dynamic_entries.value = elf_strings.offset\nWHERE elf_dynamic_entries.tag = 'NEEDED'\"\n┌───────────────────────────────────────────┬───────────────┐\n│                   path                    │     value     │\n│ extension.cpython-311-x86_64-linux-gnu.so │ libcblas.so.3 │\n│ extension.cpython-311-x86_64-linux-gnu.so │ libc.so.6     │\n└───────────────────────────────────────────┴───────────────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eDetermine the RPATH/RUNPATH entries for a program\u003c/summary\u003e\n\n_This may be improved in the future but for now there is a little knowledge of the\npolymorphic nature of the dynamic entries needed_.\n\nThe below uses a file built with [NixOS](https://nixos.org) as they all have RUNPATH set.\n\n```console\n❯ sqlelf /nix/store/gjr9ylm023rl9di484g1wxcd1jp84xxv-nix-2.8.1/bin/nix \\\n --sql \"SELECT elf_strings.path, elf_strings.value\nFROM elf_dynamic_entries\nINNER JOIN elf_strings ON elf_dynamic_entries.value = elf_strings.offset\nWHERE elf_dynamic_entries.tag = 'RUNPATH';\"\n┌─────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐\n│                      path                       │                                                                                 value                                                                                 │\n├─────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤\n│ /nix/store/gjr9ylm023rl9di484g1wxcd1jp84xxv-    │ /nix/store/gjr9ylm023rl9di484g1wxcd1jp84xxv-                                                                                                                          │\n│ nix-2.8.1/bin/nix                               │ nix-2.8.1/lib:/nix/store/pkxyfwarcq081rybpbnprjmnkiy1cz6g-libsodium-1.0.18/lib:/nix/store/r6mrf9pz4dpax6rcszcmbyrpsk8j6saz-                                           │\n│                                                 │ editline-1.17.1/lib:/nix/store/ppm63lvkyfa58sgcnr2ddzh14dy1k9fn-boehm-gc-8.0.6/lib:/nix/store/sgw2i15l01rwxzj62745h30bsjmh7wc1-lowdown-0.11.1-                        │\n│                                                 │ lib/lib:/nix/store/bvy2z17rzlvkx2sj7fy99ajm853yv898-glibc-2.34-210/lib:/nix/store/gka59hya7l7qp26s0rydcgq8hj0d7v7k-gcc-11.3.0-lib/lib                                 │\n└─────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘\n```\n\nA recursive query can further be used to split the row into multiple rows.\n\n```console\n❯ sqlelf /nix/store/gjr9ylm023rl9di484g1wxcd1jp84xxv-nix-2.8.1/bin/nix \\\n--sql \"WITH split(rpath, str) AS (\n    SELECT '', elf_strings.value||':' as rpath\n    FROM elf_dynamic_entries\n    INNER JOIN elf_strings ON elf_dynamic_entries.value = elf_strings.offset\n    WHERE elf_dynamic_entries.tag = 'RUNPATH'\n    UNION ALL SELECT\n    substr(str, 0, instr(str, ':')),\n    substr(str, instr(str, ':')+1)\n    FROM split WHERE str!=''\n) SELECT rpath FROM split WHERE rpath!='';\"\nWARNING:root:SQLITE_LOG: automatic index on elf_strings(offset) (284) SQLITE_WARNING SQLITE_WARNING_AUTOINDEX\n┌────────────────────────────────────────────────────────────────────┐\n│                               rpath                                │\n│ /nix/store/gjr9ylm023rl9di484g1wxcd1jp84xxv-nix-2.8.1/lib          │\n│ /nix/store/pkxyfwarcq081rybpbnprjmnkiy1cz6g-libsodium-1.0.18/lib   │\n│ /nix/store/r6mrf9pz4dpax6rcszcmbyrpsk8j6saz-editline-1.17.1/lib    │\n│ /nix/store/ppm63lvkyfa58sgcnr2ddzh14dy1k9fn-boehm-gc-8.0.6/lib     │\n│ /nix/store/sgw2i15l01rwxzj62745h30bsjmh7wc1-lowdown-0.11.1-lib/lib │\n│ /nix/store/bvy2z17rzlvkx2sj7fy99ajm853yv898-glibc-2.34-210/lib     │\n│ /nix/store/gka59hya7l7qp26s0rydcgq8hj0d7v7k-gcc-11.3.0-lib/lib     │\n└────────────────────────────────────────────────────────────────────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eFind the Top10 largest functions by source lines\u003c/summary\u003e\n\nThe below uses [Debuginfod](https://debuginfod.debian.net/) to fetch the DWARF file for a given binary automatically.\n\n```console\n❯ sqlelf $(DEBUGINFOD_URLS=\"https://debuginfod.debian.net\" debuginfod-find debuginfo /bin/bash) --sql \\\n\"SELECT DDL.filename, DIES.name, COUNT(DISTINCT DDL.line) AS line_count\nFROM dwarf_dies AS DIES\nJOIN dwarf_debug_lines DDL ON DIES.cu_offset = DDL.cu_offset\nWHERE DDL.address \u003e= DIES.low_pc AND DDL.address \u003c DIES.high_pc\n      AND tag = 'DW_TAG_subprogram'\n       AND name IS NOT NULL\nGROUP BY DDL.filename, DIES.name\nORDER BY line_count DESC\nLIMIT 10;\"\n┌────────────────────────────────────────┬────────────────────────────┬────────────┐\n│                filename                │            name            │ line_count │\n│ ./build-bash/subst.c                   │ param_expand               │ 665        │\n│ read.c                                 │ read_builtin               │ 500        │\n│ ./build-bash/subst.c                   │ expand_word_internal       │ 461        │\n│ ./build-bash/shell.c                   │ main                       │ 439        │\n│ ./build-bash/lib/readline/display.c    │ update_line                │ 408        │\n│ ./build-bash/lib/readline/histexpand.c │ history_expand             │ 401        │\n│ ./build-bash/y.tab.c                   │ yyparse                    │ 395        │\n│ declare.c                              │ declare_internal           │ 378        │\n│ ./build-bash/variables.c               │ initialize_shell_variables │ 345        │\n│ ./build-bash/lib/readline/display.c    │ rl_redisplay               │ 342        │\n└────────────────────────────────────────┴────────────────────────────┴────────────┘\n\n``````\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eFind the largest functions by binary size\u003c/summary\u003e\n\n```console\n❯ sqlelf examples/nested-symbols/exe --sql \\\n\"SELECT name AS function_name,\n        (high_pc - low_pc) AS function_size\nFROM dwarf_dies\nWHERE tag = 'DW_TAG_subprogram'\nORDER BY function_size DESC\nLIMIT 10;\"\n┌────────────────┬───────────────┐\n│ function_name  │ function_size │\n│ outer_function │ 38            │\n│ main           │ 21            │\n└────────────────┴───────────────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003ePrint the instructions associated with a symbol\u003c/summary\u003e\n\n```console\n❯ sqlelf /bin/bash --sql \\\n\"SELECT EI.address, ES.name, mnemonic, operands, EI.size\nFROM ELF_SYMBOLS ES\nJOIN ELF_INSTRUCTIONS EI\nON EI.PATH = ES.PATH\nWHERE\nEI.address \u003e= ES.value\nAND EI.address \u003c= ES.value + ES.size\nAND ES.name = 'read_builtin'\nORDER BY EI.address ASC LIMIT 10;\"\n┌─────────┬──────────────┬──────────┬──────────────────────┬──────┐\n│ address │     name     │ mnemonic │       operands       │ size │\n│ 689120  │ read_builtin │ push     │ r15                  │ 2    │\n│ 689122  │ read_builtin │ push     │ r14                  │ 2    │\n│ 689124  │ read_builtin │ push     │ r13                  │ 2    │\n│ 689126  │ read_builtin │ xor      │ r13d, r13d           │ 3    │\n│ 689129  │ read_builtin │ push     │ r12                  │ 2    │\n│ 689131  │ read_builtin │ xor      │ r12d, r12d           │ 3    │\n│ 689134  │ read_builtin │ push     │ rbp                  │ 1    │\n│ 689135  │ read_builtin │ lea      │ rbp, [rip + 0x5ddf3] │ 7    │\n│ 689142  │ read_builtin │ push     │ rbx                  │ 1    │\n│ 689143  │ read_builtin │ lea      │ rbx, [rip + 0x5de46] │ 7    │\n└─────────┴──────────────┴──────────┴──────────────────────┴──────┘\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eTop 10 libraries that are linked to\u003c/summary\u003e\n\nThis query assumes you have created a sqlite database from a\ncomplete distribution using [docker2sqlef](./tools/docker2sqlelf).\n\n```console\n❯ sqlite3 debian-stable-20230612.sqlite \u003c\u003cEOF\nheredoc\u003e SELECT library_basename, COUNT(*) as dependency_count\nFROM (\n    SELECT DISTINCT binary_path, library_basename\n    FROM (\n    SELECT REPLACE(imported_symbols.path,\n                       RTRIM(imported_symbols.path,\n                             REPLACE(imported_symbols.path, '/', '')\n                             ),\n                        '') AS binary_path,\n               imported_symbols.name AS symbol_name,\n               REPLACE(exported_symbols.path,\n                       RTRIM(exported_symbols.path,\n                             REPLACE(exported_symbols.path, '/', '')\n                             ),\n                        '') AS library_basename\n        FROM elf_symbols AS imported_symbols\n        INNER JOIN elf_symbols AS exported_symbols \n                ON imported_symbols.name = exported_symbols.name \n        -- Join with NEEDED entries \n        INNER JOIN elf_dynamic_entries AS needed \n                ON imported_symbols.path = needed.path\n            JOIN elf_strings\n                ON needed.value = elf_strings.offset\n                AND needed.tag = 'NEEDED'\n        WHERE imported_symbols.imported = 1\n            AND exported_symbols.exported = 1\n            AND elf_strings.value = library_basename\n    )\n)\nGROUP BY library_basename\nORDER BY dependency_count DESC\nLIMIT 10;\nheredoc\u003e EOF\n\nlibrary_basename      dependency_count\n--------------------  ----------------\nlibc.so.6             775             \nlibselinux.so.1       61              \nlibpam.so.0           57              \nlibaudit.so.1         39              \nld-linux-x86-64.so.2  35              \nlibgcc_s.so.1         31              \nlibstdc++.so.6        29              \nlibblkid.so.1         28              \nlibapt-pkg.so.6.0     27              \nlibcom_err.so.2       25\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eTop 10 libraries based on number of symbols that are used \u003c/summary\u003e\n\nThis query assumes you have created a sqlite database from a\ncomplete distribution using [docker2sqlef](./tools/docker2sqlelf).\n\n```console\n❯ sqlite3 debian-stable-20230612.sqlite \u003c\u003cEOF\nheredoc\u003e SELECT library_basename, COUNT(*) as import_count\nFROM (\n    SELECT REPLACE(imported_symbols.path,\n                       RTRIM(imported_symbols.path,\n                             REPLACE(imported_symbols.path, '/', '')\n                             ),\n                        '') AS binary_path,\n               imported_symbols.name AS symbol_name,\n               REPLACE(exported_symbols.path,\n                       RTRIM(exported_symbols.path,\n                             REPLACE(exported_symbols.path, '/', '')\n                             ),\n                        '') AS library_basename\n        FROM elf_symbols AS imported_symbols\n        INNER JOIN elf_symbols AS exported_symbols \n                ON imported_symbols.name = exported_symbols.name \n        -- Join with NEEDED entries \n        INNER JOIN elf_dynamic_entries AS needed \n                ON imported_symbols.path = needed.path\n            JOIN elf_strings\n                ON needed.value = elf_strings.offset\n                AND needed.tag = 'NEEDED'\n        WHERE imported_symbols.imported = 1\n            AND exported_symbols.exported = 1\n            AND elf_strings.value = library_basename\n)\nGROUP BY library_basename\nORDER BY import_count DESC\nLIMIT 10;\n\nheredoc\u003e EOF\nlibrary_basename   import_count\n-----------------  ------------\nlibc.so.6          353023      \nlibext2fs.so.2     6358        \nlibstdc++.so.6     3381        \nlibapt-pkg.so.6.0  3363        \nlibnettle.so.8     896         \nlibselinux.so.1    785         \nlibtinfo.so.6      723         \nlibblkid.so.1      705         \nlibgmp.so.10       592         \nlibpam.so.0        428\n```\n\n\u003c/details\u003e\n\n## Development\n\nYou may want to install the package in _editable mode_ as well to make\ndevelopment easier.\n\n```console\n\u003e python3 -m venv venv\n\u003e source venv/bin/activate\n\u003e pip install --editable \".[dev]\"\n```\n\nA helping `Makefile` is provided to run all the _linters_ and _formatters_.\n\n```console\n\u003e make lint\n\u003e make fmt\n```\n\n### Nix\n\nYou can also develop with [Nix](https://nixos.org).\nRunning the development shell should drop you into a shell with all the\nrequired dependencies and the editable installation already done.\n\n```console\n\u003e nix develop\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzakaria%2Fsqlelf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffzakaria%2Fsqlelf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzakaria%2Fsqlelf/lists"}