{"id":21168515,"url":"https://github.com/jetbrains-research/bitcode-tools","last_synced_at":"2025-04-13T14:35:27.274Z","repository":{"id":208559834,"uuid":"718728264","full_name":"JetBrains-Research/bitcode-tools","owner":"JetBrains-Research","description":"Gradle tools to analyze bitcode of a Kotlin/Native project","archived":false,"fork":false,"pushed_at":"2024-03-11T10:05:18.000Z","size":171,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-27T05:34:51.922Z","etag":null,"topics":["analysis-pipeline","bitcode","bitcode-generation","gradle","gradle-kotlin-dsl","gradle-plugin","kotlin-native","kotlin-native-plugin"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","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/JetBrains-Research.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2023-11-14T17:19:02.000Z","updated_at":"2024-10-31T16:08:22.000Z","dependencies_parsed_at":"2024-03-11T11:29:14.667Z","dependency_job_id":"458105b6-8a33-4ff4-b126-c37d80658385","html_url":"https://github.com/JetBrains-Research/bitcode-tools","commit_stats":null,"previous_names":["glebsolovev/bitcode-tools"],"tags_count":1,"template":false,"template_full_name":"cortinico/kotlin-gradle-plugin-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JetBrains-Research%2Fbitcode-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JetBrains-Research%2Fbitcode-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JetBrains-Research%2Fbitcode-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JetBrains-Research%2Fbitcode-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JetBrains-Research","download_url":"https://codeload.github.com/JetBrains-Research/bitcode-tools/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248729062,"owners_count":21152340,"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":["analysis-pipeline","bitcode","bitcode-generation","gradle","gradle-kotlin-dsl","gradle-plugin","kotlin-native","kotlin-native-plugin"],"created_at":"2024-11-20T15:14:43.772Z","updated_at":"2025-04-13T14:35:27.245Z","avatar_url":"https://github.com/JetBrains-Research.png","language":"Kotlin","readme":"# Bitcode tools for Kotlin/Native projects 🄺🄽🐘\n\n[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)\n[![Checks](https://github.com/JetBrains-Research/bitcode-tools/actions/workflows/checks.yaml/badge.svg?branch=main)](https://github.com/JetBrains-Research/bitcode-tools/actions/workflows/checks.yaml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Contributions welcome](https://img.shields.io/badge/Contributions-welcome-brightgreen.svg?style=flat)](#contributing--developing)\n\nA simple **Gradle plugin** that provides tasks **to obtain and analyze bitcode** for any Kotlin/Native projects.\n\n*Authors:* Gleb Solovev, Evgenii Moiseenko, and Anton Podkopaev, [Programming Languages and Program Analysis (PLAN) Lab](https://lp.jetbrains.com/research/plt_lab/) at JetBrains Research.\n\n- [Bitcode tools for Kotlin/Native projects 🄺🄽🐘](#bitcode-tools-for-kotlinnative-projects-)\n  - [TL;DR](#tldr)\n  - [Why analyze bitcode?](#why-analyze-bitcode)\n  - [Key features](#key-features)\n  - [Set up necessary dependencies](#set-up-necessary-dependencies)\n    - [Python dependencies](#python-dependencies)\n    - [LLVM dependency](#llvm-dependency)\n  - [Apply plugin](#apply-plugin)\n  - [Set up plugin](#set-up-plugin)\n    - [Required set-up](#required-set-up)\n    - [Access debug tasks](#access-debug-tasks)\n    - [Select `extractBitcode` targets](#select-extractbitcode-targets)\n    - [Set up `extractBitcode` working mode](#set-up-extractbitcode-working-mode)\n    - [Configure directories and file names](#configure-directories-and-file-names)\n  - [Plugin configuration examples](#plugin-configuration-examples)\n    - [Minimal configuration](#minimal-configuration)\n    - [Enable debug tasks](#enable-debug-tasks)\n    - [Select which targets and how to extract](#select-which-targets-and-how-to-extract)\n    - [Customize directories and file names](#customize-directories-and-file-names)\n  - [Call tasks in the command line](#call-tasks-in-the-command-line)\n    - [Examples](#examples)\n  - [Advanced customization](#advanced-customization)\n    - [Configure stand-alone tasks](#configure-stand-alone-tasks)\n    - [Create your own tasks](#create-your-own-tasks)\n  - [Contributing \\\u0026 developing](#contributing--developing)\n\n## TL;DR\n\nRun through the README quickly! ⚡️\n\n* Get to know the [key features](#key-features) of the plugin.\n* Make sure all [necessary dependencies](#set-up-necessary-dependencies) are set.\n* [Apply the plugin](#apply-plugin) to your Kotlin/Native project.\n* Check the examples of the [plugin configuration](#plugin-configuration-examples) and [task calls](#examples) to quickly master the plugin. \n  * An [example Kotlin/Native project](./example/build.gradle.kts) configured with the plugin might also be helpful.\n\n## Why analyze bitcode?\n\nThe pipeline for compiling Kotlin/Native code into an executable binary is as follows: first, the code is compiled into LLVM bitcode \u0026mdash; a special assembly-like language used by the framework \u0026mdash; and then LLVM converts the bitcode into the final output file.\n\nWhile some optimizations happen at the very last stage, a huge number of them (including all Kotlin-specific optimizations) happen during compilation to bitcode. Therefore, bitcode analysis of Kotlin/Native code ***becomes especially useful for***:\n* exploration of optimizations and transformations applied to the code;\n* debugging the compilation process.\n\nIn general, bitcode analysis of Kotlin/Native projects is in some ways quite similar to bytecode analysis of Kotlin/JVM code. However, since the first one is much more difficult to obtain and explore manually, the current plugin is here to help you! 🦸 \n\n## Key features\n\nUse consice Kotlin DSL syntax to configure the plugin in your `build.gradle.kts` file and get bitcode analysis tasks in return.\n* ***Analyze bitcode of your Kotlin/Native project.***\n  * `decompileBitcode` \u0026mdash; builds a human-readable `.ll` bitcode file of your source code;\n  * `extractBitcode` \u0026mdash; extracts the specified elements from the project's bitcode;\n  * *(optional)* `decompileBitcodeDebug` and `extractBitcodeDebug` \u0026mdash; additional versions of above tasks to analyze bitcode of your project built in the debug mode.\n* ***Analyze any bitcode files.***\n  * `decompileSomeBitcode` \u0026mdash; decompiles a bitcode `*.bc` file into a human-readable `*.ll` one;\n  * `extractSomeBitcode` \u0026mdash; extracts the specified elements from a bitcode `*.ll` file.\n* ***Create your own custom tasks*** using `DecompileBitcodeTask` and `ExtractBitcodeTask` classes.\n\nOf course, all tasks provided by the plugin...\n* ...support accurate inputs/outputs tracking \u0026mdash; meaning that actual work will only be done when necessary 😴; \n* ...are properly linked to the project's build tasks \u0026mdash; so no thinking about working pipeline is needed, just call the tasks 🤝;\n* ...provide set-up of their parameters both in the build file and in the command line \u0026mdash; communicate with the plugin in the most convenient way for you 🫂. \n\n## Set up necessary dependencies\n\nThe plugin requires two dependencies installed on your machine to work properly: **Python with necessary modules** and **LLVM**.\n\n### Python dependencies\n\nFirst, make sure you have Python compatible with the `3.10` version on your computer.\n```bash\npython3 --version\n```\n\nThen install the `llvmlite` module.\n```bash\npip3 install llvmlite~=0.41.0\n```\n\n### LLVM dependency\n\nThe key and the only one dependency needed from LLVM is the `llvm-dis` tool. Unfortunately, that requires installing the complete LLVM distribution and, unfortunately, we don't know any way to do it easily on the *Windows* machines so far. \n\nTo install the LLVM on your machine it is recommended to check the various guides on the Internet.\n\nOnce you finish, make sure LLVM is accessible and is compatible with the `14.0.0` version.\n```bash\nllvm-config --version\n```\n\n## Apply plugin\n\nSince the plugin was published at Gradle Plugin Portal, it can be simply applied by id in your `build.gradle.kts`. The plugin's version is mandatory, the latest is [`1.0.0`](https://github.com/JetBrains-Research/bitcode-tools/releases/tag/v1.0.0).\n\n```kotlin\nplugins {\n    kotlin(\"multiplatform\")\n    // ... other plugins you might have\n    id(\"org.jetbrains.bitcodetools.plugin\") version \"1.0.0\"\n}\n``` \nIf your working in IDE, it'd better to rebuild Gradle at this point, so to access the lovely DSL auto-completion 🤖.\n\n## Set up plugin\n\nThe next step is plugin configuration. There are two extensions available in `build.gradle.kts` to do this: `decompileBitcodeConfig` and `extractFromDecompiledBitcodeConfig`.\n\n### Required set-up\n\nThe only set-up being required is the following one:\n```kotlin\ndecompileBitcodeConfig {\n    linkTaskName = \"the name of the task to link your Kotlin/Native sources\" \n    setCompilerFlags = { compilerFlags: List\u003cString\u003e -\u003e\n        // add `compilerFlags` to your Kotlin/Native compiler\n    }\n}\n```\nCheck [examples section](#plugin-configuration-examples) to see ready-to-use code snippets. \n\nNow plugin already provides `decompileBitcode` and `extractBitcode` tasks to analyze your project's bitcode and `decompileSomeBitcode` and `extractSomeBitcode` tasks to analyze some standalone bitcode files.\n\n### Access debug tasks\n\nTo get `decompileBitcodeDebug` and `extractBitcodeDebug` tasks to analyze debug build of your project, the `linkDebugTaskName` should be set too.\n```kotlin\ndecompileBitcodeConfig {\n    // ... other properties set-up\n    linkDebugTaskName = \"the name of the task to link your Kotlin/Native sources in the debug mode\"\n}\n```\n\n### Select `extractBitcode` targets\n\n`extractBitcode` and `extractBitcodeDebug` tasks extracts the target functions defined in the `extractFromDecompiledBitcodeConfig`. So far, you can select the targets in the following way.\n```kotlin\nextractFromDecompiledBitcodeConfig {\n    functionNames = listOf(\"name of the function, specified exactly as in the bitcode file\")\n    functionPatterns = listOf(\"regex pattern to match the desired function names\")\n    linePatterns = listOf(\"regex pattern to match at least one line of bitcode of the desired functions\")\n    ignorePatterns = listOf(\"regex pattern to ignore functions with their name matching it\")\n}\n```\nSince all these properties are `ListProperty`-s, you can always add new elements to them with `.add(...)` syntax.\n```kotlin\nfunctionNames.add(\"desired function names\")\n```  \nSee more examples in the [examples section](#plugin-configuration-examples).\n\n### Set up `extractBitcode` working mode\n\nExtract-bitcode tasks provide several properties, to configure the way the perform the extraction.\n\nThe property `recursionDepth` enables ***recursive exraction*** of all called functions up to the specified depth (relative to the target functions). Zero value (the default one) means recursive extraction is disabled: only target functions will be extracted.\n```kotlin\nextractFromDecompiledBitcodeConfig {\n    // ... other properties set-up\n    recursionDepth = 1u // additionaly extracts all functions called from the target functions \n}\n```\n\nThe property `verbose` simply enables logging printed to the stdout. It can be useful to track the extraction process thoroughly, but might be too verbose in case you extract a lot of functions at a time.\n```kotlin\nextractFromDecompiledBitcodeConfig {\n    // ... other properties set-up\n    verbose = true // enables logging (disabled by default)\n}\n```\n\n### Configure directories and file names\n\nEven though the plugin by default uses the most common names and paths for the input and output files, you still might want to customize them. To do this, consider the following properties. \n\n```kotlin\ndecompileBitcodeConfig {\n    // ... other properties set-up\n    artifactsDirectoryPath = \"path to the directory to store all the input and output bitcode artifacts (relative to the project directory), 'build/bitcode' by default\"\n    bcInputFileName = \"name of the '*.bc' file produced by the link task, 'out.bc' by default\"\n    llOutputFileName = \"name of the '*.ll' file to decompile bitcode into, 'bitcode.ll' by default\"\n    llDebugOutputFileName = \"name of the '*.ll' file to decompile debug bitcode into, 'bitcode-debug.ll' by default\"\n}\n\nextractFromDecompiledBitcodeConfig {\n    // ... other properties set-up\n    outputFileName = \"name of the file to save extracted bitcode into, 'extracted-bitcode.ll' by default\"\n    debugOutputFileName = \"name of the file to save extracted debug bitcode into, 'extracted-bitcode-debug.ll' by default\"\n}\n```\nHowever, if you experiment with bitcode a lot generating many different result files for different configurations, it might be more convenient to set up the names of the files via command line flags. Check the [command-line section](#call-tasks-in-the-command-line). \n\n## Plugin configuration examples\n\nHere you can find several ready-to-use code snippets, which also clarify the syntax described above. Besides, you can find *an example Kotlin/Native project configured with the plugin* at the [`example`](example/build.gradle.kts) directory.\n\n### Minimal configuration\n\nMinimal configuration to build and analyze bitcode of a standard Kotlin/Native project on a `LinuxX64` machine.\n\n```kotlin\ndecompileBitcodeConfig {\n    linkTaskName = \"linkReleaseExecutableLinuxX64\"\n    setCompilerFlags = { compilerFlags -\u003e\n        kotlin {\n            linuxX64().compilations.getByName(\"main\") {\n                kotlinOptions.freeCompilerArgs += compilerFlags\n            }\n        }\n    }\n}\n```\n\nMinimal configuration for a standard Kotlin/Native project to support any machine architecture.\n```kotlin\ndecompileBitcodeConfig {\n    val hostOs: String = System.getProperty(\"os.name\")\n    val arch: String = System.getProperty(\"os.arch\")\n    linkTaskName = when {\n        hostOs == \"Linux\" -\u003e \"linkReleaseExecutableLinuxX64\"\n        hostOs == \"Mac OS X\" \u0026\u0026 arch == \"x86_64\" -\u003e \"linkReleaseExecutableMacosX64\"\n        hostOs == \"Mac OS X\" \u0026\u0026 arch == \"aarch64\" -\u003e \"linkReleaseExecutableMacosArm64\"\n        hostOs.startsWith(\"Windows\") -\u003e throw GradleException(\"Windows is currently unsupported: unable to install `llvm-dis` tool\")\n        else -\u003e throw GradleException(\"Unsupported target platform: $hostOs / $arch\")\n    }\n    setCompilerFlags = { compilerFlags -\u003e\n        kotlin {\n            listOf(macosX64(), macosArm64(), mingwX64(), linuxX64()).forEach {\n                it.compilations.getByName(\"main\") {\n                    kotlinOptions.freeCompilerArgs += compilerFlags\n                }\n            }\n        }\n    }\n}\n```\n\n### Enable debug tasks\n\nAn easy way to get the debug tasks for a standard Kotlin/Native project.\n```kotlin\ndecompileBitcodeConfig {\n    // ... other properties set-up\n    linkDebugTaskName = linkTaskName.replace(\"Release\", \"Debug\")\n}\n```\n\n### Select which targets and how to extract\n\nAn example of selecting the targets to extract from the project's bitcode.\n```kotlin\nextractFromDecompiledBitcodeConfig {\n    // extract these two functions: main and exception-throwing\n    functionNames = listOf(\"kfun:#main(){}\", \"ThrowIllegalArgumentException\")\n\n    // additionally, extract all the functions that contain `main` in their names as a substring\n    functionPatterns = listOf(\".*main.*\")\n\n    // also extract functions that either contain the following exact code line or rather any call to some `hashCode` function\n    linePatterns.add(\"%2 = icmp eq i64 %1, 0\")\n    linePatterns.add(\".*call.*kfun:.*#hashCode\\\\(\\\\)\\\\{\\\\}kotlin\\\\.Int.*\")\n\n    // ignore functions from the standard library, otherwise they most likely litter the analysis\n    ignorePatterns.add(\"kfun:kotlin.*\")\n}\n```\n\nTune the behaviour of the `extractBitcode` and `extractBitcodeDebug` tasks.\n```kotlin\nextractFromDecompiledBitcodeConfig {\n    // ... other properties set-up\n\n    // choose which depth makes sense for you to examine the calls inside the target functions\n    recursionDepth = 3u\n\n    // track the extraction process via the log messages\n    verbose = true\n}\n```\n\n### Customize directories and file names \n\nDefine custom file directories and file names for the tasks.\n```kotlin\ndecompileBitcodeConfig {\n    // ... other properties set-up\n    \n    // defines the parent directory for all the bitcode artifacts generated by the pipeline tasks, relative to the project's root\n    artifactsDirectoryPath = \"build/customBitcodeDir\"\n\n    // be careful changing this file name: your task provided in the `linkTask` should generate exactly this file in the provided directory via `-Xtemporary-files-dir` flag (it's easier just to check it on practice by running the `decompileBitcode` task)\n    bcInputFileName = \"main.bc\"\n\n    // choose the file names you like, the decompiled bitcode will appear in these files in the `artifactsDirectoryPath` directory\n    llOutputFileName = \"decompiled-bitcode.ll\"\n    llDebugOutputFileName = \"decompiled-bitcode-debug.ll\"\n}\n\nextractFromDecompiledBitcodeConfig {\n    // ... other properties set-up\n\n    // simple customization of the output files names, they will be generated in the `artifactsDirectoryPath` too\n    outputFileName = \"extracted-bitcode.ll\"\n    debugOutputFileName = \"extracted-bitcode-debug.ll\"\n\n    // P.S. you can't change the input file name, because `extractBitcode` / `extractBitcodeDebug` tasks are pipeline ones: they accept `llOutputFileName` / `llDebugOutputFileName` from the `decompileBitcode` / `decompileBitcodeDebug` tasks as an input\n}\n```\n\n## Call tasks in the command line\n\nAs for any other Gradle tasks, one of the easiest way to run the bitcode ones is to call them via `gradle` / `./gradlew` from the command line. Also if your IDE supports Gradle tasks execution from the GUI, this could also be an option.\n\n```bash\n# runs `decompileBitcode` task found in the project\ngradle decompileBitcode\n\n# does the same, you just use the script in the root directory to call Gradle\n./gradlew decompileBitcode\n\n# runs `decompileBitcode` task for the `example` subproject\ngradle :example:decompileBitcode\n```\n\nWhile the plugin set-up defines the default arguments of the tasks (so they can be called just as-is), these arguments can be overriden by ones specified in the command line. \n\nAlmost all settings from the set-up section can be passed by the command line flags. To check their full list just call the `help` task.\n\n```bash\ngradle help --task decompileBitcode\ngradle help --task extractBitcode\n```\n\n### Examples\n\nCalling `decompileBitcode` / `decompileDebugBitcode` / `decompileSomeBitcode` tasks.\n\n```bash\n# call with arguments configured in the build files\ngradle decompileBitcode\n\n# override input and output file paths\ngradle decompileBitcode --input build/bitcode/releaseSources/out.bc --output build/bitcode/bitcode.ll\n```\n\nCalling `extractBitcode` / `extractBitcodeDebug` / `extractSomeBitcode` tasks.\n\n```bash\n# call with arguments configured in the build files\ngradle extractBitcode\n\n# override input (*) and output file paths\n# note: the input path should match the output file of the corresponding `decompileBitcode` task\ngradle extractBitcode --input build/bitcode/bitcode.ll --output build/bitcode/extracted-bitcode.ll\n\n# select targets to extract: \n    # main and exception-throwing functions;\n    # all the functions that contain `main` in their names as a substring;\n    # all the functions that contain call to some `hashCode` function;\n    # ignoring functions from the standard library\n# note: don't forget to quote the arguments, otherwise your console may try to interpret them as regexes by itself\ngradle extractBitcode --function 'kfun:#main(){}' --function 'ThrowIllegalArgumentException' --function-pattern '.*main.*' --line-pattern '.*call.*kfun:.*#hashCode\\(\\)\\{\\}kotlin\\.Int.*' --ignore-function-pattern 'kfun:kotlin.*'\n\n# extract main function and all functions that are called from its body with the detailed logging enabled\ngradle extractBitcode --function-pattern 'kfun:#main\\(.*' --recursion-depth=1 --verbose\n```\n\n## Advanced customization\n\nTwo Gradle extensions `decompileBitcodeConfig` and `extractFromDecompiledBitcodeConfig` provide a great way to set up the pipeline tasks to analyze your project's bitcode. But there is still place for the customization of the stand-alone `decompileSomeBitcode` and `extractSomeBitcode` tasks and even creating your own Gradle machinery.\n\n### Configure stand-alone tasks\n\nIf you tend to use the same arguments of the stand-alone task frequently, they can be moved to the `build.gradle.kts` as default ones just for convenience. Here is an example.\n\n```kotlin\ntasks.named\u003cDecompileBitcodeTask\u003e(\"decompileSomeBitcode\") {\n    outputFilePath = \"build/bitcode/bitcode.ll\"\n}\n\ntasks.named\u003cExtractBitcodeTask\u003e(\"extractSomeBitcode\") {\n    recursionDepth = 1u\n    verbose = true\n}\n```\n\n### Create your own tasks\n\nAll tasks provided by the plugin are of the task classes `DecompileBitcodeTask` and `ExtractBitcodeTask`, actually the plugin only makes their set-up easier. Thus, if you feel the provided tasks are not enough for your goals, you can always register your own ones and freely configure them with all the power of Gradle!\n\n```kotlin\ntasks.register\u003cDecompileBitcodeTask\u003e(\"decompileMyBitcode\") {}\n\ntasks.register\u003cExtractBitcodeTask\u003e(\"extractMyBitcode\") {\n    verbose = True\n}\n\ntasks.register\u003cExtractBitcodeTask\u003e(\"extractBitcodePolitely\") {\n    dependsOn(\"decompileBitcode\")\n    doFirst {\n        println(\"It's impolite not to say hello at the very beginning. So, hello!\")\n    }\n    inputFilePath = \"build/bitcode/bitcode.ll\"\n    outputFilePath = \"build/bitcode/custom-bitcode.ll\"\n    functionNames = listOf(\"kfun:#main(){}\")\n}\n```\nOf course, all the `DecompileBitcodeTaks` and `ExtractBitcodeTask` tasks get command-line flags support just out-of-the-box, so there is no limitations on calling your custom tasks in the command line.\n\n## Contributing \u0026 developing\n\nIf you have any ideas on improving the project or found any bugs, you're always welcome to contact any of the authors or support an issue 🫂\n\nIn case you're interested in the more development details of this project, make sure to check the [DEVELOPMENT_GUIDE.md](./DEVELOPMENT_GUIDE.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetbrains-research%2Fbitcode-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjetbrains-research%2Fbitcode-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetbrains-research%2Fbitcode-tools/lists"}