Squashed 'external/ircolib/' changes from ce3cd726c..de6e324bd
de6e324bdseparate emu thread10d3daf86Roms List improvements95d202f37Let's make the rom list process on a separate thread so the emulator doesnt take ages to load.fc306967fWow the ROM Header was just completely busted. Game list view works nowbad1691eefuck this shit2b59e5f46game list in progressd26417b83remappable inputs in progressac4af8106inpute72abc240update readme430139dc9Qt6 frontend3080d4d45Fix this small bug too08cd13b85Cop0 unused functions do not actually pose a threat (as per manual). They don't do anything, so shall we.61bb4fb44make idle loop detection a little more specific with where the load goesb037de4c3SAZDFsdff12e81e73eneed to figure out why n64-systemtest loops indefinitely at some address that appears to be valid (i think it's me not invalidating the cache properly)204f0e13bidle skipping seems to work!cb8bb634asdkfjlasdf58e5c89c1Fix compilation issue on my machine (no idea)24fb2898eattempting more serious idle skipping214719577Place rsp.Step inside cached interpreter. Gains about 3 more fpsbb97dcc23mmmmm920b77d38wjkhasdfjhkasdf430ccdab4it's a start...4f42a673aCached interpreter plays Mario 64. Start looking into RSP as wellc9a030787idle skipping works!5fbda03cenew idea366637abaIdle skipping... maybe?609fa2fb0Cache instructions implemented but broken lmao. Commented out for nowe140a6d12- Stop using inheritance for CPU, instead use composition. - Introduce KAIZEN_JIT_ENABLED optional define instead of relying on __aarch64__ and the like. - More cache work68e613057prep cache impl811b4d809fix clang formatfda755f7didkd5024ebbfsmall MI refactor in preparation of (eventually) implementing the RDRAM interface properly694b45341Merge commit '206dcdedf195fb320913584180edb12c7731e396' as 'external/SDL'206dcdedfSquashed 'external/SDL/' content from commit 4d17b99d0a4d16e1cb4need to update sdl848b19920Fix compilation errordb61b5299Merge commit 'e94a94559f28e49678fbcf72199a5258137b0fe9' as 'external/imgui'e94a94559Squashed 'external/imgui/' content from commit 02e9b8cac52edb3757need to update imguic1a705e86Emulate weird JALR behaviour4b4c32f4bFix exception for "unusable COP1" in 4 instructions i missed accidentally (again)df5828142Bug putting 0s in the log everywheref8b580048Make isviewer a sink to file8241e9735Fix exception for "unusable COP1" in 4 instructions i missed accidentallyb29715f20small changesd9a620bc1make use of my new small utility library0d1aa938eAdd 'external/ircolib/' from commit 'ce3cd726c8df8388d554abf8bb55d55020eb4450'e64eb40b3Fuck git git-subtree-dir: external/ircolib git-subtree-split:de6e324bde
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
build/
|
||||
vendor/llvm_root
|
||||
*/.idea
|
||||
src/auto-sync/config.json
|
||||
src/autosync/cpptranslator/Tests/Differ/test_saved_patches.json
|
||||
src/autosync.egg-info
|
||||
src/autosync/Tests/MCUpdaterTests/ARCH/Output
|
||||
src/autosync/Tests/MCUpdaterTests/Disassembler/ARCH/Output
|
||||
src/autosync/lit_config/test_dir_*
|
||||
src/autosync/lit_config/.lit_test_times.txt
|
||||
src/autosync/Tests/MCUpdaterTests/test_output
|
||||
src/autosync/Tests/MCUpdaterTests/test_output_fuzz
|
||||
src/autosync/Tests/MCUpdaterTests/**/Output
|
||||
src/autosync/cpptranslator/Tests/Differ/output/*.c
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
<!--
|
||||
Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
SPDX-License-Identifier: BSD-3
|
||||
-->
|
||||
|
||||
# Architecture of the Auto-Sync framework
|
||||
|
||||
This document is split into four parts.
|
||||
|
||||
1. An overview of the update process and which subcomponents of `auto-sync` do what.
|
||||
2. The instructions how to update an architecture which already supports `auto-sync`.
|
||||
3. Instructions how to refactor an architecture to use `auto-sync`.
|
||||
4. Notes about how to add a new architecture to Capstone with `auto-sync`.
|
||||
|
||||
Please read the section about capstone module design in
|
||||
[ARCHITECTURE.md](https://github.com/capstone-engine/capstone/blob/next/docs/ARCHITECTURE.md) before proceeding.
|
||||
The architectural understanding is important for the following.
|
||||
|
||||
## Update procedure
|
||||
|
||||
As already described in the `ARCHITECTURE` document, Capstone uses translated
|
||||
and generated source code from LLVM.
|
||||
|
||||
Because LLVM is written in C++ and Capstone in C the update process is
|
||||
internally complicated but almost completely automated.
|
||||
|
||||
`auto-sync` categorizes source files of a module into three groups. Each group is updated differently.
|
||||
|
||||
| File type | Update method | Edits by hand |
|
||||
|-----------------------------------|----------------------|------------------------|
|
||||
| Generated files | Generated by patched LLVM backends | Never/Not allowed |
|
||||
| Translated LLVM C++ files | `CppTranslater` and `Differ` | Only changes which are too complicated for automation. |
|
||||
| Capstone files | By hand | all |
|
||||
|
||||
Let's look at the update procedure for each group in detail.
|
||||
|
||||
**Note**: The only exception to touch generated files is via git patches. This is the last resort
|
||||
if something is broken in LLVM, and we cannot generate correct files.
|
||||
|
||||
**Generated files**
|
||||
|
||||
Generated files always have the file extension `.inc`.
|
||||
|
||||
There are generated files for the LLVM code and for Capstone. They can be distinguished by their names:
|
||||
|
||||
- For Capstone: `<ARCH>GenCS<NAME>.inc`.
|
||||
- For LLVM code: `<ARCH>Gen<NAME>.inc`.
|
||||
|
||||
The files are generated by refactored [LLVM TableGen emitter backends](https://github.com/capstone-engine/llvm-capstone/tree/dev/llvm/utils/TableGen).
|
||||
|
||||
The procedure looks roughly like this:
|
||||
|
||||
```
|
||||
┌──────────┐
|
||||
1 2 3 4 │CS .inc │
|
||||
┌───────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌─►│files │
|
||||
│ .td │ │ │ │ │ │ Code- │ │ └──────────┘
|
||||
│ files ├────►│ TableGen ├────►│ CodeGen ├────►│ Emitter ├──┤
|
||||
└───────┘ └──────┬────┘ └───────────┘ └──────────┘ │ ┌──────────┐
|
||||
│ ▲ └─►│LLVM .inc │
|
||||
└─────────────────────────────────┘ │files │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
|
||||
1. LLVM architectures are defined in `.td` files. They describe instructions, operands,
|
||||
features and other properties of an architecture.
|
||||
|
||||
2. [LLVM TableGen](https://llvm.org/docs/TableGen/index.html) parses these files
|
||||
and converts them to an internal representation.
|
||||
|
||||
3. In the second step a TableGen component called [CodeGen](https://llvm.org/docs/CodeGenerator.html)
|
||||
abstracts the these properties even further.
|
||||
The result is a representation which is _not_ specific to any architecture
|
||||
(e.g. the `CodeGenInstruction` class can represent a machine instruction of any architecture).
|
||||
|
||||
4. The `Code-Emitter` uses the abstract representation of the architecture (provided from `CodeGen`) to
|
||||
generated state machines for instruction decoding.
|
||||
Architecture specific information (think of register names, operand properties etc.)
|
||||
is taken from `TableGen's` internal representation.
|
||||
|
||||
The result is emitted to `.inc` files. Those are included in the translated C++ files or Capstone code where necessary.
|
||||
|
||||
**Translation of LLVM C++ files**
|
||||
|
||||
We use two tools to translate C++ to C files.
|
||||
|
||||
First the `CppTranslator` and afterward the `Differ`.
|
||||
|
||||
The `CppTranslator` parses the C++ files and patches C++ syntax
|
||||
with its equivalent C syntax.
|
||||
|
||||
_Note_: For details about this checkout `suite/auto-sync/CppTranslator/README.md`.
|
||||
|
||||
Because the result of the `CppTranslator` is not perfect,
|
||||
we still have many syntax problems left.
|
||||
|
||||
Those need to be fixed partially by hand.
|
||||
|
||||
**Differ**
|
||||
|
||||
In order to ease this process we run the `Differ` after the `CppTranslator`.
|
||||
|
||||
The `Differ` compares our two versions of C files we have now.
|
||||
One of them are the C files currently used by the architecture module.
|
||||
On the other hand we have the translated C files. Those are still faulty and need to be fixed.
|
||||
|
||||
Most fixes are syntactical problems. Those were almost always resolved before, during the last update.
|
||||
The `Differ` helps you to compare the files and let you select which version to accept.
|
||||
|
||||
Sometimes (not very often though), the newly translated C files contain important changes.
|
||||
Most often though, the old files are already correct.
|
||||
|
||||
The `Differ` parses both files into an abstract syntax tree and compares certain nodes with the same name
|
||||
(mostly functions).
|
||||
|
||||
The user can choose if she accepts the version from the translated file or the old file.
|
||||
This decision is saved for every node.
|
||||
If there exists a saved decision for two nodes, and the nodes did not change since the last time,
|
||||
it applies the previous decision automatically again.
|
||||
|
||||
The `Differ` is far from perfect. It only helps to automatically apply "known to be good" fixes
|
||||
and gives the user a better interface to solve the other problems.
|
||||
But there will still be syntax errors left afterward. These must be fixed by hand.
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
<!--
|
||||
Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
SPDX-License-Identifier: BSD-3
|
||||
-->
|
||||
|
||||
# Architecture updater - Auto-Sync
|
||||
|
||||
`Auto-Sync` is the architecture update tool for Capstone.
|
||||
Because the architecture modules of Capstone use mostly code from LLVM,
|
||||
we need to update this part with every LLVM release. `Auto-Sync` helps
|
||||
with this synchronization between LLVM and Capstone's modules by
|
||||
automating most of it.
|
||||
|
||||
Please refer to [intro.md](intro.md) for an introduction about this tool.
|
||||
|
||||
## Install
|
||||
|
||||
#### Setup Python environment and Tree-sitter
|
||||
|
||||
```
|
||||
cd <root-dir-Capstone>
|
||||
# Python version must be at least 3.11
|
||||
sudo apt install python3-venv
|
||||
# Setup virtual environment in Capstone root dir
|
||||
python3 -m venv ./.venv
|
||||
source ./.venv/bin/activate
|
||||
```
|
||||
|
||||
#### Install Auto-Sync framework
|
||||
|
||||
```
|
||||
cd suite/auto-sync/
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
#### Clone Capstones LLVM fork and build `llvm-tblgen`
|
||||
|
||||
```bash
|
||||
git clone https://github.com/capstone-engine/llvm-capstone vendor/llvm_root/
|
||||
cd vendor/llvm_root/llvm-capstone
|
||||
git checkout auto-sync
|
||||
mkdir build
|
||||
cd build
|
||||
# You can also build the "Release" version
|
||||
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../llvm
|
||||
cmake --build . --target llvm-tblgen --config Debug
|
||||
cd <capstone-root>/suite/auto-sync/
|
||||
```
|
||||
|
||||
#### Install `llvm-mc` and `FileCheck`
|
||||
|
||||
Additionally, we need `llvm-mc` and `FileCheck` to generate our regression tests.
|
||||
You can build it, but it will take a lot of space on your hard drive.
|
||||
You can also get the binaries [here](https://releases.llvm.org/download.html) or
|
||||
install it with your package manager (usually something like `llvm-18-dev`).
|
||||
Just ensure it is in your `PATH` as `llvm-mc` and `FileCheck` (not as `llvm-mc-18` or similar though!).
|
||||
|
||||
## Architecture
|
||||
|
||||
Please read [ARCHITECTURE.md](https://github.com/capstone-engine/capstone/blob/next/docs/ARCHITECTURE.md) to understand how `Auto-Sync` works.
|
||||
|
||||
This step is essential! Please don't skip it.
|
||||
|
||||
## Update an architecture
|
||||
|
||||
Updating an architecture module to the newest LLVM release, is only possible if it uses `Auto-Sync`.
|
||||
Not all arch-modules support `Auto-Sync` yet.
|
||||
|
||||
Check if your architecture is supported.
|
||||
|
||||
```
|
||||
ASUpdater -h
|
||||
```
|
||||
|
||||
Run the updater
|
||||
|
||||
```
|
||||
ASUpdater -a <ARCH>
|
||||
```
|
||||
|
||||
## Update procedure
|
||||
|
||||
1. Run the `ASUpdater` script.
|
||||
2. Compare the functions in `<ARCH>DisassemblerExtension.*` to LLVM (search the function names in the LLVM root)
|
||||
and update them if necessary (some architectures don't have this file).
|
||||
3. Try to build Capstone and fix the build errors.
|
||||
|
||||
|
||||
## Post-processing steps
|
||||
|
||||
This update translates some LLVM C++ files to C.
|
||||
Because the translation is not perfect (maybe it will some day)
|
||||
you will get build errors if you try to compile Capstone.
|
||||
|
||||
The last step to finish the update is to fix those build errors by hand.
|
||||
|
||||
## Refactor an architecture
|
||||
|
||||
Not all architecture modules support `Auto-Sync` yet.
|
||||
Here is an overview of the steps to add support for it.
|
||||
|
||||
<hr>
|
||||
|
||||
To refactor one of them to use `Auto-Sync` please follow the [RefactorGuide.md](RefactorGuide.md)
|
||||
|
||||
## Adding a new architecture
|
||||
|
||||
Adding a new architecture follows the same steps as above. With the exception that you need
|
||||
to implement all the Capstone files from scratch.
|
||||
|
||||
Check out an `Auto-Sync` supporting architectures for guidance and open an issue if you need help.
|
||||
|
||||
## Additional details
|
||||
|
||||
### Overview updated files
|
||||
|
||||
This is a rough overview what files of an architecture are updated and where they are coming from.
|
||||
|
||||
**Files originating from LLVM** (Automatically updated)
|
||||
|
||||
These files are LLVM source files which were translated from C++ to C
|
||||
Not all the listed files below are used by each architecture.
|
||||
But those are the most common.
|
||||
|
||||
- `<ARCH>Disassembler.*`: Bytes to `MCInst` decoder.
|
||||
- `<ARCH>InstPrinter.*` or `<ARCH>AsmPrinter.*`: `MCInst` to asm string decoder.
|
||||
- `<ARCH>BaseInfo.*`: Commonly use functions and definitions.
|
||||
|
||||
`*.inc` files are exclusively generated by LLVM TableGen backends:
|
||||
|
||||
`*.inc` files for the LLVM component are named like this:
|
||||
- `<ARCH>Gen*.inc` (note: no `CS` in the name)
|
||||
|
||||
Additionally, we generate more details for Capstone with `llvm-tblgen`.
|
||||
Like enums, operand details and other things.
|
||||
|
||||
They are saved also to `*.inc` files, but have the `CS` in the name to make them distinct from the LLVM generated files.
|
||||
|
||||
- `<ARCH>GenCS*.inc`
|
||||
|
||||
**Capstone module files** (Not automatically updated)
|
||||
|
||||
Those files are written by us:
|
||||
|
||||
- `<ARCH>DisassemblerExtension.*` All kind of functions which are needed by the LLVM component, but could not be generated or translated.
|
||||
- `<ARCH>Mapping.*`: Binding code between the architecture module and the LLVM files. This is also where the detail is set.
|
||||
- `<ARCH>Module.*`: Interface to the Capstone core.
|
||||
|
||||
### Relevant documentation and troubleshooting
|
||||
|
||||
**LLVM file translation**
|
||||
|
||||
For details about the C++ to C translation of the LLVM files refer to `CppTranslator/README.md`.
|
||||
|
||||
**Generated .inc files**
|
||||
|
||||
Documentation about the `.inc` file generation is in the [llvm-capstone](https://github.com/capstone-engine/llvm-capstone) repository.
|
||||
|
||||
**Troubleshooting**
|
||||
|
||||
- If some features aren't generated and are missing in the `.inc` files, make sure they are defined as `AssemblerPredicate` in the `.td` files.
|
||||
|
||||
Correct:
|
||||
```
|
||||
def In32BitMode : Predicate<"!Subtarget->isPPC64()">,
|
||||
AssemblerPredicate<(all_of (not Feature64Bit)), "64bit">;
|
||||
```
|
||||
Incorrect:
|
||||
```
|
||||
def In32BitMode : Predicate<"!Subtarget->isPPC64()">;
|
||||
```
|
||||
|
||||
**Formatting**
|
||||
|
||||
- If you make changes to the `CppTranslator` please format the files with `black` and `usort`
|
||||
```
|
||||
pip3 install black usort
|
||||
python3 -m usort format src/autosync
|
||||
python3 -m black src/autosync
|
||||
```
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# Refactor guide
|
||||
|
||||
This is a step by step overview how to refactor an architecture.
|
||||
|
||||
It can also be used to add a new architecture module. As long as it is supported by LLVM or a fork of it.
|
||||
|
||||
Please always contact us in the [Auto-Sync tracking issue](https://github.com/capstone-engine/capstone/issues/2015)
|
||||
before working on a module.
|
||||
We can provide support and save you a lot of time.
|
||||
|
||||
Don't hesitate to ask any questions in our [Telegram Community channel](https://t.me/CapstoneEngine).
|
||||
|
||||
Especially if you feel stuck or struggle to understand where an issue is coming from.
|
||||
The update process is, although already simplified, relatively complex.
|
||||
|
||||
## Refactoring
|
||||
|
||||
Note:
|
||||
- If we talk about C++ files in the steps below, we always refer to the files in the LLVM repo.
|
||||
- `PrinterCapstone` is the class defined in `llvm-capstone/llvm/utils/TabelGen/PrinterCapstone.cpp`
|
||||
- Always attempt to make the translated C file behave as closely as possible to the original C++ file! This greatly helps debugging and assures that Capstone behaves almost exactly the same as original LLVM.
|
||||
|
||||
- ### Prepare
|
||||
- Read `CONTRIBUTING.md`
|
||||
- Read `docs/ARCHITECTURE.md`
|
||||
- Read `suite/auto-sync/README.md`
|
||||
- Read `suite/auto-sync/ARCHITECTURE.md`
|
||||
- Read `suite/auto-sync/intro.md`
|
||||
- Delete all files in `arch/<ARCH>/`, except the `ARCHModule.*` and `ARCHMapping.*`.
|
||||
- `cd suite/auto-sync/`
|
||||
- ### Generate `inc` files
|
||||
- `pip install -e .`
|
||||
- Clone and build `llvm-tblgen` (see docs)
|
||||
- Quickly check options of the updater `ASUpdater -h`
|
||||
- Add Arch name in `Target.py`
|
||||
- In [llvm-capstone](https://github.com/capstone-engine/llvm-capstone) handle arch in `PrinterCapstone.cpp::decoderEmitterEmitFieldFromInstruction()` (add decoder function)
|
||||
- Generate: `ASUpdater -s IncGen -a ARCH`
|
||||
- Errors? Check if the error message tells you what to do. If no hint exists, ask us.
|
||||
- Check if `inc` files in `build` look good.
|
||||
- ### Translation and Patching
|
||||
- Check for template functions in `<ARCH>InstPrinter.cpp` and `<ARCH>Disassember.cpp`
|
||||
- Copy new config in `arch_conf.json` (LoongArch for a minimal example).
|
||||
- Don't forget to add `ARCHIntPrinter.cpp` to the list of the `AddCSDetail` tests!
|
||||
- Add as a minimum the `<ARCH>InstPrinter.cpp`, `<ARCH>InstPrinter.h` and `<ARCH>Disassembler.cpp` to the translation list.
|
||||
- Tip: The variables use in there are defined in `path_vars.json`
|
||||
- Add architecture specific includes in `Patches/Includes.py`. Copy the code from another architecture for the beginning.
|
||||
- Prepare API header (`<arch>.h`) for patching:
|
||||
- Check the generated `inc` files. Files names like `<ARCH>GenCS<something>Enum.inc` contain enumerations for the header. Those get patched into the main header file of the architecture.
|
||||
- Remove old values and add `// generated content <...> begin` comments for patching. Checkout `longarch.h` as example.
|
||||
- Commit all changes so far.
|
||||
- The next step will write to the `arch/` and `include/capstone/<arch>.h` header!
|
||||
- Run generation, translation and copy/patch the files: `ASUpdater -a <ARCH> -w --copy-translated -s IncGen Translate PatchArchHeader`
|
||||
- ### Clean up
|
||||
- #### Check: All necessary files
|
||||
- Arch header:
|
||||
- Invalid characters in enum identifiers? Replace char in `PrinterCapstone::normalizedMnemonic`
|
||||
- In `arch/<ARCH>`
|
||||
- Missing identifier/symbols? -> Check if they are somewhere in the generated files. If yes, included them and update `Include.py`. If not, you have to find the LLVM source file where they are defined and add it to the `arch_config.json` to translate it.
|
||||
- OR it needs the `SystemOperands.inc` file. Also can be generated by adding the arch to the list in `inc_gen.json`.
|
||||
- Note: When you start the next step, you likely don't want to generate, translate and copy files again. Because your had-made fixes get overwritten. So ensure you no longer use the `-w` flag for the `ASUpdater` and you checked thoroughly that all necessary files got translated!
|
||||
- Commit to save changes so far.
|
||||
- #### Remove and fix C++ syntax
|
||||
- Remove all **obvious irrelevant** C++ code from the translated files (e.g. class initializes)
|
||||
- Double check non-obvious cases, if they are important. Rember: removing something might lead to bugs later!
|
||||
- If in doubt, ask us.
|
||||
- If you fix the same syntax over and over again, consider adding a Patch for the `CppTranslator`.
|
||||
- Common problems:
|
||||
- Missing namespace prefix `unsigned GR32Regs[]` should be `unsigned ARCH_GR32Regs[]`. See `namespace begin/end` comments in the code.
|
||||
- TODO: Add more.
|
||||
- If in doubt, check the original C++ file in the LLVM repo.
|
||||
- ### Make it build
|
||||
- Add `ARCHLinkage.h` and the functions in the `InstPrinter.c`, `ArchDisassembler.c`.
|
||||
- Add essential code in `ARCHMapping.c`. Esential is everything **not** releated to details.
|
||||
- If unsure how to do Capstone <-> LLVM code things, always check LoongArch. If LoongArch doesn't handle this case, check Mips, SystemZ
|
||||
- ### Run tests & Fixing bugs
|
||||
- Update regression MC tests: Map LLVM `mattr` and `mcpu` names to the CS identifiers if necessary. -> Edit the `mcupdater.json` config file.
|
||||
- Update tests: `ASUpdater -s MCUpdate -a Arch -w`
|
||||
- Run MC tests: `cstest tests/MC/Arch`
|
||||
- ### Add details
|
||||
- Effectively copy behavior from `LoongArchMapping.c` or `SystemZMapping.c` but change values.
|
||||
- Changes to the API (structs in `arch.h`) are only allowed if it was wrong before. Otherwise only extensions.
|
||||
- Don't forget to update the Python bindings.
|
||||
- Run detail tests to check results.
|
||||
- Run detail tests with coverage. `ArchMapping.c` should be covered near 100%
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
# The reglist operands are immediates. These immediates are technically read.
|
||||
# But for Capstone we want every register in the least to be written (for load instructions).
|
||||
# Hence, we patch it here.
|
||||
diff --git a/arch/ARM/ARMGenCSMappingInsnOp.inc b/arch/ARM/ARMGenCSMappingInsnOp.inc
|
||||
index cc10dad8..8a1ede35 100644
|
||||
--- a/arch/ARM/ARMGenCSMappingInsnOp.inc
|
||||
+++ b/arch/ARM/ARMGenCSMappingInsnOp.inc
|
||||
@@ -4925,32 +4925,32 @@
|
||||
{ /* ARM_FLDMXDB_UPD (851) - ARM_INS_FLDMDBX - fldmdbx${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_FLDMXIA (852) - ARM_INS_FLDMIAX - fldmiax${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_FLDMXIA_UPD (853) - ARM_INS_FLDMIAX - fldmiax${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_FMSTAT (854) - ARM_INS_VMRS - vmrs${p} APSR_nzcv, fpscr */
|
||||
{
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
@@ -5210,80 +5210,80 @@
|
||||
}},
|
||||
{ /* ARM_LDMDA (885) - ARM_INS_LDMDA - ldmda${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDMDA_UPD (886) - ARM_INS_LDMDA - ldmda${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDMDB (887) - ARM_INS_LDMDB - ldmdb${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDMDB_UPD (888) - ARM_INS_LDMDB - ldmdb${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDMIA (889) - ARM_INS_LDM - ldm${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDMIA_UPD (890) - ARM_INS_LDM - ldm${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDMIB (891) - ARM_INS_LDMIB - ldmib${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDMIB_UPD (892) - ARM_INS_LDMIB - ldmib${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_LDRBT_POST_IMM (893) - ARM_INS_LDRBT - ldrbt${p} $Rt, $addr, $offset */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rt */
|
||||
@@ -23132,64 +23132,64 @@
|
||||
{ /* ARM_VLDMDDB_UPD (2838) - ARM_INS_VLDMDB - vldmdb${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VLDMDIA (2839) - ARM_INS_VLDMIA - vldmia${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VLDMDIA_UPD (2840) - ARM_INS_VLDMIA - vldmia${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{{{ /* ARM_VLDMQIA (2841) - ARM_INS_INVALID - */
|
||||
0
|
||||
}}},
|
||||
{ /* ARM_VLDMSDB_UPD (2842) - ARM_INS_VLDMDB - vldmdb${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VLDMSIA (2843) - ARM_INS_VLDMIA - vldmia${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VLDMSIA_UPD (2844) - ARM_INS_VLDMIA - vldmia${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VLDRD (2845) - ARM_INS_VLDR - vldr${p} $Dd, $addr */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_f64, CS_DATA_TYPE_v8i8, CS_DATA_TYPE_v4i16, CS_DATA_TYPE_v2i32, CS_DATA_TYPE_v1i64, CS_DATA_TYPE_v2f32, CS_DATA_TYPE_v4f16, CS_DATA_TYPE_v4bf16, CS_DATA_TYPE_LAST } }, /* Dd */
|
||||
@@ -28522,21 +28522,21 @@
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VSCCLRMD (3449) - ARM_INS_VSCCLRM - vscclrm{$p} $regs */
|
||||
{
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VSCCLRMS (3450) - ARM_INS_VSCCLRM - vscclrm{$p} $regs */
|
||||
{
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_VSDOTD (3451) - ARM_INS_VSDOT - vsdot.s8 $Vd, $Vn, $Vm */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_f64, CS_DATA_TYPE_v8i8, CS_DATA_TYPE_v4i16, CS_DATA_TYPE_v2i32, CS_DATA_TYPE_v1i64, CS_DATA_TYPE_v2f32, CS_DATA_TYPE_v4f16, CS_DATA_TYPE_v4bf16, CS_DATA_TYPE_LAST } }, /* dst */
|
||||
@@ -32683,80 +32683,80 @@
|
||||
}},
|
||||
{ /* ARM_sysLDMDA (3964) - ARM_INS_LDMDA - ldmda${p} $Rn, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysLDMDA_UPD (3965) - ARM_INS_LDMDA - ldmda${p} $Rn!, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysLDMDB (3966) - ARM_INS_LDMDB - ldmdb${p} $Rn, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysLDMDB_UPD (3967) - ARM_INS_LDMDB - ldmdb${p} $Rn!, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysLDMIA (3968) - ARM_INS_LDM - ldm${p} $Rn, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysLDMIA_UPD (3969) - ARM_INS_LDM - ldm${p} $Rn!, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysLDMIB (3970) - ARM_INS_LDMIB - ldmib${p} $Rn, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysLDMIB_UPD (3971) - ARM_INS_LDMIB - ldmib${p} $Rn!, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_sysSTMDA (3972) - ARM_INS_STMDA - stmda${p} $Rn, $regs ^ */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
@@ -33633,42 +33633,42 @@
|
||||
}},
|
||||
{ /* ARM_t2LDMDB (4075) - ARM_INS_LDMDB - ldmdb${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_t2LDMDB_UPD (4076) - ARM_INS_LDMDB - ldmdb${p} $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_t2LDMIA (4077) - ARM_INS_LDM - ldm${p}.w $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_t2LDMIA_UPD (4078) - ARM_INS_LDM - ldm${p}.w $Rn!, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* wb */
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_t2LDRBT (4079) - ARM_INS_LDRBT - ldrbt${p} $Rt, $addr */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rt */
|
||||
@@ -36683,13 +36683,13 @@
|
||||
}}},
|
||||
{ /* ARM_tLDMIA (4413) - ARM_INS_LDM - ldm${p} $Rn, $regs */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rn */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
{ /* ARM_tLDRBi (4414) - ARM_INS_LDRB - ldrb${p} $Rt, $addr */
|
||||
{
|
||||
{ CS_OP_REG, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* Rt */
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
diff --git a/arch/ARM/ARMGenAsmWriter.inc b/arch/ARM/ARMGenAsmWriter.inc
|
||||
index b8b7182d..59d4e510 100644
|
||||
--- a/arch/ARM/ARMGenAsmWriter.inc
|
||||
+++ b/arch/ARM/ARMGenAsmWriter.inc
|
||||
@@ -10011,18 +10011,15 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 14:
|
||||
// FCONSTD, VABSD, VADDD, VCMPD, VCMPED, VCMPEZD, VCMPZD, VDIVD, VFMAD, V...
|
||||
SStream_concat0(O, ".f64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F64);
|
||||
printOperand(MI, 0, O);
|
||||
break;
|
||||
case 15:
|
||||
// FCONSTH, MVE_VABDf16, MVE_VABSf16, MVE_VADD_qr_f16, MVE_VADDf16, MVE_V...
|
||||
SStream_concat0(O, ".f16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F16);
|
||||
break;
|
||||
case 16:
|
||||
// FCONSTS, MVE_VABDf32, MVE_VABSf32, MVE_VADD_qr_f32, MVE_VADDf32, MVE_V...
|
||||
SStream_concat0(O, ".f32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F32);
|
||||
break;
|
||||
case 17:
|
||||
// FMSTAT
|
||||
@@ -10047,47 +10044,38 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 21:
|
||||
// MVE_VABAVs16, MVE_VABDs16, MVE_VABSs16, MVE_VADDVs16acc, MVE_VADDVs16n...
|
||||
SStream_concat0(O, ".s16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S16);
|
||||
break;
|
||||
case 22:
|
||||
// MVE_VABAVs32, MVE_VABDs32, MVE_VABSs32, MVE_VADDLVs32acc, MVE_VADDLVs3...
|
||||
SStream_concat0(O, ".s32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S32);
|
||||
break;
|
||||
case 23:
|
||||
// MVE_VABAVs8, MVE_VABDs8, MVE_VABSs8, MVE_VADDVs8acc, MVE_VADDVs8no_acc...
|
||||
SStream_concat0(O, ".s8\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S8);
|
||||
break;
|
||||
case 24:
|
||||
// MVE_VABAVu16, MVE_VABDu16, MVE_VADDVu16acc, MVE_VADDVu16no_acc, MVE_VC...
|
||||
SStream_concat0(O, ".u16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U16);
|
||||
break;
|
||||
case 25:
|
||||
// MVE_VABAVu32, MVE_VABDu32, MVE_VADDLVu32acc, MVE_VADDLVu32no_acc, MVE_...
|
||||
SStream_concat0(O, ".u32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U32);
|
||||
break;
|
||||
case 26:
|
||||
// MVE_VABAVu8, MVE_VABDu8, MVE_VADDVu8acc, MVE_VADDVu8no_acc, MVE_VCMPu8...
|
||||
SStream_concat0(O, ".u8\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U8);
|
||||
break;
|
||||
case 27:
|
||||
// MVE_VADC, MVE_VADCI, MVE_VADD_qr_i32, MVE_VADDi32, MVE_VBICimmi32, MVE...
|
||||
SStream_concat0(O, ".i32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_I32);
|
||||
break;
|
||||
case 28:
|
||||
// MVE_VADD_qr_i16, MVE_VADDi16, MVE_VBICimmi16, MVE_VCADDi16, MVE_VCLZs1...
|
||||
SStream_concat0(O, ".i16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_I16);
|
||||
break;
|
||||
case 29:
|
||||
// MVE_VADD_qr_i8, MVE_VADDi8, MVE_VCADDi8, MVE_VCLZs8, MVE_VCMPi8, MVE_V...
|
||||
SStream_concat0(O, ".i8\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_I8);
|
||||
break;
|
||||
case 30:
|
||||
// MVE_VCTP64, MVE_VSTRD64_qi, MVE_VSTRD64_qi_pre, MVE_VSTRD64_rq, MVE_VS...
|
||||
@@ -10097,14 +10085,12 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 31:
|
||||
// MVE_VCVTf16f32bh, MVE_VCVTf16f32th, VCVTBSH, VCVTTSH, VCVTf2h
|
||||
SStream_concat0(O, ".f16.f32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F16F32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
break;
|
||||
case 32:
|
||||
// MVE_VCVTf16s16_fix, MVE_VCVTf16s16n, VCVTs2hd, VCVTs2hq, VCVTxs2hd, VC...
|
||||
SStream_concat0(O, ".f16.s16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F16S16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10112,7 +10098,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 33:
|
||||
// MVE_VCVTf16u16_fix, MVE_VCVTf16u16n, VCVTu2hd, VCVTu2hq, VCVTxu2hd, VC...
|
||||
SStream_concat0(O, ".f16.u16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F16U16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10120,7 +10105,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 34:
|
||||
// MVE_VCVTf32f16bh, MVE_VCVTf32f16th, VCVTBHS, VCVTTHS, VCVTh2f
|
||||
SStream_concat0(O, ".f32.f16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F32F16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10129,7 +10113,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 35:
|
||||
// MVE_VCVTf32s32_fix, MVE_VCVTf32s32n, VCVTs2fd, VCVTs2fq, VCVTxs2fd, VC...
|
||||
SStream_concat0(O, ".f32.s32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F32S32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10137,7 +10120,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 36:
|
||||
// MVE_VCVTf32u32_fix, MVE_VCVTf32u32n, VCVTu2fd, VCVTu2fq, VCVTxu2fd, VC...
|
||||
SStream_concat0(O, ".f32.u32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F32U32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10145,7 +10127,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 37:
|
||||
// MVE_VCVTs16f16_fix, MVE_VCVTs16f16a, MVE_VCVTs16f16m, MVE_VCVTs16f16n,...
|
||||
SStream_concat0(O, ".s16.f16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S16F16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10153,7 +10134,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 38:
|
||||
// MVE_VCVTs32f32_fix, MVE_VCVTs32f32a, MVE_VCVTs32f32m, MVE_VCVTs32f32n,...
|
||||
SStream_concat0(O, ".s32.f32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S32F32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10161,7 +10141,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 39:
|
||||
// MVE_VCVTu16f16_fix, MVE_VCVTu16f16a, MVE_VCVTu16f16m, MVE_VCVTu16f16n,...
|
||||
SStream_concat0(O, ".u16.f16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U16F16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10169,7 +10148,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 40:
|
||||
// MVE_VCVTu32f32_fix, MVE_VCVTu32f32a, MVE_VCVTu32f32m, MVE_VCVTu32f32n,...
|
||||
SStream_concat0(O, ".u32.f32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U32F32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10188,19 +10166,16 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 43:
|
||||
// MVE_VLDRDU64_qi, MVE_VLDRDU64_qi_pre, MVE_VLDRDU64_rq, MVE_VLDRDU64_rq...
|
||||
SStream_concat0(O, ".u64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U64);
|
||||
break;
|
||||
case 44:
|
||||
// MVE_VMOVimmi64, VADDHNv2i32, VADDv1i64, VADDv2i64, VMOVNv2i32, VMOVv1i...
|
||||
SStream_concat0(O, ".i64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_I64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
break;
|
||||
case 45:
|
||||
// MVE_VMULLBp16, MVE_VMULLTp16
|
||||
SStream_concat0(O, ".p16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_P16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10211,7 +10186,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 46:
|
||||
// MVE_VMULLBp8, MVE_VMULLTp8, VMULLp8, VMULpd, VMULpq
|
||||
SStream_concat0(O, ".p8\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_P8);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10232,7 +10206,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 49:
|
||||
// VCVTBDH, VCVTTDH
|
||||
SStream_concat0(O, ".f16.f64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F16F64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 2, O);
|
||||
@@ -10241,7 +10214,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 50:
|
||||
// VCVTBHD, VCVTTHD
|
||||
SStream_concat0(O, ".f64.f16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F64F16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10250,7 +10222,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 51:
|
||||
// VCVTDS
|
||||
SStream_concat0(O, ".f64.f32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F64F32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10259,7 +10230,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 52:
|
||||
// VCVTSD
|
||||
SStream_concat0(O, ".f32.f64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F32F64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10268,7 +10238,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 53:
|
||||
// VJCVT, VTOSIRD, VTOSIZD, VTOSLD
|
||||
SStream_concat0(O, ".s32.f64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S32F64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10339,14 +10308,12 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 67:
|
||||
// VQADDsv1i64, VQADDsv2i64, VQMOVNsuv2i32, VQMOVNsv2i32, VQRSHLsv1i64, V...
|
||||
SStream_concat0(O, ".s64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
break;
|
||||
case 68:
|
||||
// VSHTOD
|
||||
SStream_concat0(O, ".f64.s16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F64S16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10357,7 +10324,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 69:
|
||||
// VSHTOS
|
||||
SStream_concat0(O, ".f32.s16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F32S16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10368,7 +10334,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 70:
|
||||
// VSITOD, VSLTOD
|
||||
SStream_concat0(O, ".f64.s32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F64S32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10376,7 +10341,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 71:
|
||||
// VSITOH, VSLTOH
|
||||
SStream_concat0(O, ".f16.s32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F16S32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10384,7 +10348,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 72:
|
||||
// VTOSHD
|
||||
SStream_concat0(O, ".s16.f64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S16F64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10395,7 +10358,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 73:
|
||||
// VTOSHS
|
||||
SStream_concat0(O, ".s16.f32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S16F32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10406,7 +10368,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 74:
|
||||
// VTOSIRH, VTOSIZH, VTOSLH
|
||||
SStream_concat0(O, ".s32.f16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_S32F16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10414,7 +10375,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 75:
|
||||
// VTOUHD
|
||||
SStream_concat0(O, ".u16.f64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U16F64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10425,7 +10385,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 76:
|
||||
// VTOUHS
|
||||
SStream_concat0(O, ".u16.f32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U16F32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10436,7 +10395,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 77:
|
||||
// VTOUIRD, VTOUIZD, VTOULD
|
||||
SStream_concat0(O, ".u32.f64\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U32F64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10444,7 +10402,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 78:
|
||||
// VTOUIRH, VTOUIZH, VTOULH
|
||||
SStream_concat0(O, ".u32.f16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_U32F16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10452,7 +10409,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 79:
|
||||
// VUHTOD
|
||||
SStream_concat0(O, ".f64.u16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F64U16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10463,7 +10419,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 80:
|
||||
// VUHTOS
|
||||
SStream_concat0(O, ".f32.u16\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F32U16);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10474,7 +10429,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 81:
|
||||
// VUITOD, VULTOD
|
||||
SStream_concat0(O, ".f64.u32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F64U32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -10482,7 +10436,6 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
case 82:
|
||||
// VUITOH, VULTOH
|
||||
SStream_concat0(O, ".f16.u32\t");
|
||||
+ ARM_add_vector_data(MI, ARM_VECTORDATA_F16U32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
@@ -0,0 +1,90 @@
|
||||
diff --git a/arch/ARM/ARMGenAsmWriter.inc b/arch/ARM/ARMGenAsmWriter.inc
|
||||
index 33fa7815..b8b7182d 100644
|
||||
--- a/arch/ARM/ARMGenAsmWriter.inc
|
||||
+++ b/arch/ARM/ARMGenAsmWriter.inc
|
||||
@@ -9939,28 +9939,31 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
// Fragment 1 encoded into 7 bits for 89 unique commands.
|
||||
switch ((Bits >> 19) & 127) {
|
||||
default: CS_ASSERT_RET(0 && "Invalid command number.");
|
||||
case 0:
|
||||
// ASRi, ASRr, ITasm, LDRBT_POST, LDRConstPool, LDRHTii, LDRSBTii, LDRSHT...
|
||||
SStream_concat1(O, ' ');
|
||||
break;
|
||||
case 1:
|
||||
// VLD1LNdAsm_16, VLD1LNdWB_fixed_Asm_16, VLD1LNdWB_register_Asm_16, VLD2...
|
||||
SStream_concat0(O, ".16\t");
|
||||
+ ARM_add_vector_size(MI, 16);
|
||||
break;
|
||||
case 2:
|
||||
// VLD1LNdAsm_32, VLD1LNdWB_fixed_Asm_32, VLD1LNdWB_register_Asm_32, VLD2...
|
||||
SStream_concat0(O, ".32\t");
|
||||
+ ARM_add_vector_size(MI, 32);
|
||||
break;
|
||||
case 3:
|
||||
// VLD1LNdAsm_8, VLD1LNdWB_fixed_Asm_8, VLD1LNdWB_register_Asm_8, VLD2LNd...
|
||||
SStream_concat0(O, ".8\t");
|
||||
+ ARM_add_vector_size(MI, 8);
|
||||
break;
|
||||
case 4:
|
||||
// t2LDRB_OFFSET_imm, t2LDRB_POST_imm, t2LDRB_PRE_imm, t2LDRH_OFFSET_imm,...
|
||||
SStream_concat0(O, ".w ");
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
break;
|
||||
case 5:
|
||||
// ADCri, ADCrr, ADCrsi, ADDri, ADDrr, ADDrsi, ADR, ANDri, ANDrr, ANDrsi,...
|
||||
SStream_concat0(O, "\t");
|
||||
@@ -10082,20 +10085,21 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
ARM_add_vector_data(MI, ARM_VECTORDATA_I16);
|
||||
break;
|
||||
case 29:
|
||||
// MVE_VADD_qr_i8, MVE_VADDi8, MVE_VCADDi8, MVE_VCLZs8, MVE_VCMPi8, MVE_V...
|
||||
SStream_concat0(O, ".i8\t");
|
||||
ARM_add_vector_data(MI, ARM_VECTORDATA_I8);
|
||||
break;
|
||||
case 30:
|
||||
// MVE_VCTP64, MVE_VSTRD64_qi, MVE_VSTRD64_qi_pre, MVE_VSTRD64_rq, MVE_VS...
|
||||
SStream_concat0(O, ".64\t");
|
||||
+ ARM_add_vector_size(MI, 64);
|
||||
break;
|
||||
case 31:
|
||||
// MVE_VCVTf16f32bh, MVE_VCVTf16f32th, VCVTBSH, VCVTTSH, VCVTf2h
|
||||
SStream_concat0(O, ".f16.f32\t");
|
||||
ARM_add_vector_data(MI, ARM_VECTORDATA_F16F32);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
break;
|
||||
case 32:
|
||||
// MVE_VCVTf16s16_fix, MVE_VCVTf16s16n, VCVTs2hd, VCVTs2hq, VCVTxs2hd, VC...
|
||||
@@ -10265,28 +10269,31 @@ static void printInstruction(MCInst *MI, uint64_t Address, SStream *O) {
|
||||
// VJCVT, VTOSIRD, VTOSIZD, VTOSLD
|
||||
SStream_concat0(O, ".s32.f64\t");
|
||||
ARM_add_vector_data(MI, ARM_VECTORDATA_S32F64);
|
||||
printOperand(MI, 0, O);
|
||||
SStream_concat0(O, ", ");
|
||||
printOperand(MI, 1, O);
|
||||
break;
|
||||
case 54:
|
||||
// VLD1LNd16, VLD1LNd16_UPD, VLD2LNd16, VLD2LNd16_UPD, VLD2LNq16, VLD2LNq...
|
||||
SStream_concat0(O, ".16\t{");
|
||||
+ ARM_add_vector_size(MI, 16);
|
||||
break;
|
||||
case 55:
|
||||
// VLD1LNd32, VLD1LNd32_UPD, VLD2LNd32, VLD2LNd32_UPD, VLD2LNq32, VLD2LNq...
|
||||
SStream_concat0(O, ".32\t{");
|
||||
+ ARM_add_vector_size(MI, 32);
|
||||
break;
|
||||
case 56:
|
||||
// VLD1LNd8, VLD1LNd8_UPD, VLD2LNd8, VLD2LNd8_UPD, VLD3DUPd8, VLD3DUPd8_U...
|
||||
SStream_concat0(O, ".8\t{");
|
||||
+ ARM_add_vector_size(MI, 8);
|
||||
break;
|
||||
case 57:
|
||||
// VLDR_FPCXTNS_off, VLDR_FPCXTNS_post, VLDR_FPCXTNS_pre, VMSR_FPCXTNS, V...
|
||||
SStream_concat0(O, "\tfpcxtns, ");
|
||||
break;
|
||||
case 58:
|
||||
// VLDR_FPCXTS_off, VLDR_FPCXTS_post, VLDR_FPCXTS_pre, VMSR_FPCXTS, VSTR_...
|
||||
SStream_concat0(O, "\tfpcxts, ");
|
||||
break;
|
||||
case 59:
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
diff --git a/arch/ARM/ARMGenCSMappingInsnOp.inc b/arch/ARM/ARMGenCSMappingInsnOp.inc
|
||||
index 749cdb85..4abfd4b8 100644
|
||||
--- a/arch/ARM/ARMGenCSMappingInsnOp.inc
|
||||
+++ b/arch/ARM/ARMGenCSMappingInsnOp.inc
|
||||
@@ -36878,7 +36878,7 @@
|
||||
{
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
{ CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* p - i32imm */
|
||||
- { CS_OP_IMM, CS_AC_READ, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
+ { CS_OP_IMM, CS_AC_WRITE, { CS_DATA_TYPE_i32, CS_DATA_TYPE_LAST } }, /* regs */
|
||||
{ CS_OP_INVALID, CS_AC_READ, { CS_DATA_TYPE_LAST } }, /* */
|
||||
{ 0 }
|
||||
}},
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
## Why the Auto-Sync framework?
|
||||
|
||||
Capstone provides a simple API to leverage the LLVM disassemblers, without
|
||||
having the big footprint of LLVM itself.
|
||||
|
||||
It does this by using a stripped down copy of LLVM disassemblers (one for each architecture)
|
||||
and provides a uniform API to them.
|
||||
|
||||
The actual disassembly task (bytes to asm-text and decoded operands) is completely done by
|
||||
the LLVM code.
|
||||
Capstone takes the disassembled instructions, adds details to them (operand read/write info etc.)
|
||||
and organizes them to a uniform structure (`cs_insn`, `cs_detail` etc.).
|
||||
These objects are then accessible from the API.
|
||||
|
||||
Capstone is in C and LLVM is in C++. So to use the disassembler modules of LLVM,
|
||||
Capstone effectively translates LLVM source files from C++ to C, without changing the semantics.
|
||||
One could also call it a "disassembler port".
|
||||
|
||||
Capstone supports multiple architectures. So whenever LLVM
|
||||
has a new release and adds more instructions, Capstone needs to update its modules as well.
|
||||
|
||||
In the past, the update procedure was done by hand and with some Python scripts.
|
||||
But the task was tedious and error-prone.
|
||||
|
||||
To ease the complicated update procedure, Auto-Sync comes in.
|
||||
|
||||
<hr>
|
||||
|
||||
## How LLVM disassemblers work
|
||||
|
||||
Because effectively use the LLVM disassembler logic, one must understand how they operate.
|
||||
|
||||
Each architecture is defined in a so-called `.td` file, that is, a "Target Description" file.
|
||||
Those files are a declarative description of an architecture.
|
||||
They are written in a Domain-Specific Language called [TableGen](https://llvm.org/docs/TableGen/).
|
||||
They contain instructions, registers, processor features, which instructions operands read and write and more information.
|
||||
|
||||
These files are consumed by "TableGen Backends". They parse and process them to generate C++ code.
|
||||
The generated code is for example: enums, decoding algorithms (for instructions and operands) or
|
||||
lookup tables for register names or alias.
|
||||
|
||||
Additionally, LLVM has handwritten files. They use the generated code to build the actual instruction classes
|
||||
and handle architecture specific edge cases.
|
||||
|
||||
Capstone uses both of those files. The generated ones as well as the handwritten ones.
|
||||
|
||||
## Overview of updating steps
|
||||
|
||||
An Auto-Sync update has multiple steps:
|
||||
|
||||
**(1)** Changes in the auto-generated C++ files are handled completely automatically,
|
||||
We have a LLVM fork with patched TableGen-backends, so they emit C code.
|
||||
|
||||
**(2)** Changes in LLVM's handwritten sources are handled semi-automatically.
|
||||
For each source file, we search C++ syntax and replace it with the equivalent C syntax.
|
||||
For this task we have the CppTranslator.
|
||||
|
||||
The end result is of course not perfectly valid C code.
|
||||
It is merely an intermediate file, which still has some C++ syntax in it.
|
||||
|
||||
Because this leftover syntax was likely already fixed in the equivalent C file currently in Capstone,
|
||||
we have a last step.
|
||||
The translated file is diffed with the corresponding old file in Capstone.
|
||||
|
||||
The `Differ` tool parses both files into an abstract syntax tree.
|
||||
From this AST it picks nodes with the same name and diffs them.
|
||||
The diff is given to the user, and they can decide which one to accept.
|
||||
|
||||
All choices are also recorded and automatically applied next time.
|
||||
|
||||
**Example**
|
||||
|
||||
> Suppose there is a file `ArchDisassembler.cpp` in LLVM.
|
||||
> Capstone has the C equivalent `ArchDisassembler.c`.
|
||||
>
|
||||
> Now LLVM has a new release, and there were several additions in `ArchDisassembler.cpp`.
|
||||
>
|
||||
> Auto-Sync will pass `ArchDisassembler.cpp` to the CppTranslator, which replaces most C++ syntax.
|
||||
> The result is an intermediate file `transl_ArchDisassembler.cpp`.
|
||||
>
|
||||
> The result is close to what we want (C code), but still contains invalid syntax.
|
||||
> Most of this syntax errors were fixed before. They must be, because the C file `ArchDisassemble.c`
|
||||
> is working fine.
|
||||
>
|
||||
> So the intermediate file `transl_ArchDisassebmler.cpp` is compared to the old `ArchDisassemble.c.
|
||||
> The Differ patches both files to an AST and automatically patches all nodes it can.
|
||||
>
|
||||
> Effectively automate most of the boring, mechanical work involved in fixing-up `transl_ArchDisassebmler.cpp`.
|
||||
> If something new came up, it asks the user for a decission.
|
||||
>
|
||||
> The result is saved to `ArchDisassembler.c`, which is now up-to-date with the newest LLVM release.
|
||||
>
|
||||
> In practice this file will still contain syntax errors. But not many, so they can easily be resolved.
|
||||
|
||||
**(3)** After (1) and (2), some changes in Capstone-only files follow.
|
||||
This step is manual work.
|
||||
@@ -0,0 +1,354 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import argparse
|
||||
|
||||
import logging as log
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import json
|
||||
from enum import StrEnum
|
||||
from pathlib import Path
|
||||
|
||||
from autosync.cpptranslator.Configurator import Configurator
|
||||
from autosync.cpptranslator.CppTranslator import Translator
|
||||
from autosync.HeaderPatcher import CompatHeaderBuilder, HeaderPatcher
|
||||
from autosync.Helper import convert_loglevel, fail_exit, get_path
|
||||
|
||||
from autosync.IncGenerator import IncGenerator
|
||||
|
||||
from autosync.MCUpdater import MCUpdater
|
||||
from autosync.Targets import ARCH_LLVM_NAMING, TARGET_TO_DIR_NAME
|
||||
|
||||
|
||||
class USteps(StrEnum):
|
||||
INC_GEN = "IncGen"
|
||||
TRANS = "Translate"
|
||||
DIFF = "Diff"
|
||||
MC = "MCUpdate"
|
||||
PATCH_HEADER = "PatchArchHeader"
|
||||
ALL = "All"
|
||||
|
||||
|
||||
class ASUpdater:
|
||||
"""
|
||||
The auto-sync updater.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
arch: str,
|
||||
write: bool,
|
||||
steps: list[USteps],
|
||||
inc_list: list,
|
||||
no_clean: bool,
|
||||
copy_translated: bool,
|
||||
differ_no_auto_apply: bool,
|
||||
wait_for_user: bool = True,
|
||||
) -> None:
|
||||
self.arch = arch
|
||||
self.arch_dir_name = TARGET_TO_DIR_NAME[self.arch]
|
||||
self.write = write
|
||||
self.no_clean_build = no_clean
|
||||
self.inc_list = inc_list
|
||||
self.wait_for_user = wait_for_user
|
||||
if USteps.ALL in steps:
|
||||
self.steps = [
|
||||
USteps.INC_GEN,
|
||||
USteps.TRANS,
|
||||
USteps.DIFF,
|
||||
USteps.MC,
|
||||
USteps.PATCH_HEADER,
|
||||
]
|
||||
else:
|
||||
self.steps = steps
|
||||
self.copy_translated = copy_translated
|
||||
self.differ_no_auto_apply = differ_no_auto_apply
|
||||
self.arch_dir = get_path("{CS_ARCH_MODULE_DIR}").joinpath(
|
||||
TARGET_TO_DIR_NAME[self.arch]
|
||||
)
|
||||
if not self.no_clean_build:
|
||||
self.clean_build_dir()
|
||||
self.inc_generator = IncGenerator(
|
||||
self.arch,
|
||||
self.inc_list,
|
||||
)
|
||||
with open(get_path("{MCUPDATER_CONFIG_FILE}")) as f:
|
||||
self.mcupdater_conf = json.loads(f.read())
|
||||
|
||||
self.mc_updater = MCUpdater(
|
||||
self.arch,
|
||||
get_path("{LLVM_MC_TEST_DIR}"),
|
||||
None,
|
||||
None,
|
||||
self.arch in self.mcupdater_conf["unify_test_cases"],
|
||||
multi_mode=True,
|
||||
)
|
||||
|
||||
def clean_build_dir(self) -> None:
|
||||
log.info("Clean build directory")
|
||||
path: Path
|
||||
for path in get_path("{BUILD_DIR}").iterdir():
|
||||
log.debug(f"Delete {path}")
|
||||
if path.is_dir():
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.remove(path)
|
||||
|
||||
def patch_main_header(self) -> list:
|
||||
"""
|
||||
Patches the main header of the arch with the .inc files.
|
||||
It returns a list of files it has patched into the main header.
|
||||
"""
|
||||
if not self.write:
|
||||
return []
|
||||
main_header = get_path("{CS_INCLUDE_DIR}").joinpath(f"{self.arch.lower()}.h")
|
||||
# Just try every inc file
|
||||
patched = []
|
||||
for file in get_path("{C_INC_OUT_DIR}").iterdir():
|
||||
patcher = HeaderPatcher(main_header, file)
|
||||
if patcher.patch_header():
|
||||
# Save the path. This file should not be moved.
|
||||
patched.append(file)
|
||||
if self.arch == "AArch64":
|
||||
builder = CompatHeaderBuilder(
|
||||
v6=main_header,
|
||||
v5=get_path("{CS_INCLUDE_DIR}").joinpath(f"arm64.h"),
|
||||
arch="aarch64",
|
||||
)
|
||||
builder.generate_v5_compat_header()
|
||||
elif self.arch == "AArch64":
|
||||
builder = CompatHeaderBuilder(
|
||||
v6=main_header,
|
||||
v5=get_path("{CS_INCLUDE_DIR}").joinpath(f"systemz_compatibility.h"),
|
||||
arch="systemz",
|
||||
)
|
||||
builder.generate_v5_compat_header()
|
||||
return patched
|
||||
|
||||
def copy_files(self, path: Path, dest: Path) -> None:
|
||||
"""
|
||||
Copies files from path to dest.
|
||||
If path is a directory it copies all files in it.
|
||||
If it is a file, it only copies it.
|
||||
"""
|
||||
if not self.write:
|
||||
return
|
||||
if not dest.is_dir():
|
||||
fail_exit(f"{dest} is not a directory.")
|
||||
|
||||
if path.is_file():
|
||||
log.debug(f"Copy {path} to {dest}")
|
||||
shutil.copy(path, dest)
|
||||
return
|
||||
|
||||
for file in path.iterdir():
|
||||
log.debug(f"Copy {path} to {dest}")
|
||||
shutil.copy(file, dest)
|
||||
|
||||
def check_tree_sitter(self) -> None:
|
||||
ts_dir = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
|
||||
if not ts_dir.exists():
|
||||
log.info("tree-sitter was not fetched. Cloning it now...")
|
||||
subprocess.run(
|
||||
["git", "submodule", "update", "--init", "--recursive"], check=True
|
||||
)
|
||||
|
||||
def translate(self) -> None:
|
||||
self.check_tree_sitter()
|
||||
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
|
||||
configurator = Configurator(self.arch, translator_config)
|
||||
translator = Translator(configurator, self.wait_for_user)
|
||||
translator.translate()
|
||||
translator.remark_manual_files()
|
||||
|
||||
def diff(self) -> None:
|
||||
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
|
||||
configurator = Configurator(self.arch, translator_config)
|
||||
from autosync.cpptranslator.Differ import Differ
|
||||
|
||||
differ = Differ(configurator, self.differ_no_auto_apply)
|
||||
differ.diff()
|
||||
|
||||
def update(self) -> None:
|
||||
if USteps.INC_GEN in self.steps:
|
||||
self.inc_generator.generate()
|
||||
if USteps.PATCH_HEADER in self.steps:
|
||||
if self.write:
|
||||
patched = self.patch_main_header()
|
||||
log.info(f"Patched {len(patched)} .inc files into the main header.")
|
||||
else:
|
||||
log.info("Patching the main header requires the -w flag.")
|
||||
if USteps.TRANS in self.steps:
|
||||
self.translate()
|
||||
if USteps.DIFF in self.steps:
|
||||
self.diff()
|
||||
if USteps.MC in self.steps:
|
||||
self.mc_updater.gen_all()
|
||||
self.mc_updater.write_to_build_dir()
|
||||
self.mc_updater.write_to_build_dir(fuzzer_tests=True)
|
||||
if not self.write:
|
||||
if self.inc_generator.has_inc_patches():
|
||||
log.warning(
|
||||
f"Patches to inc files are only applied with the -w flag. This wasn't done. Find them in {get_path('{INC_PATCH_DIR}')}"
|
||||
)
|
||||
# Done
|
||||
exit(0)
|
||||
|
||||
# Copy .inc files
|
||||
log.info(f"Copy .inc files to {self.arch_dir}")
|
||||
i = 0
|
||||
arch_header = get_path("{CS_INCLUDE_DIR}").joinpath(f"{self.arch.lower()}.h")
|
||||
for file in get_path("{C_INC_OUT_DIR}").iterdir():
|
||||
if HeaderPatcher.file_in_main_header(arch_header, file.name):
|
||||
continue
|
||||
self.copy_files(file, self.arch_dir)
|
||||
i += 1
|
||||
self.inc_generator.apply_patches()
|
||||
log.info(f"Copied {i} files")
|
||||
|
||||
i = 0
|
||||
if self.copy_translated:
|
||||
# Diffed files
|
||||
log.info(f"Copy translated files to {self.arch_dir}")
|
||||
for file in get_path("{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}").iterdir():
|
||||
self.copy_files(file, self.arch_dir)
|
||||
i += 1
|
||||
else:
|
||||
# Diffed files
|
||||
log.info(f"Copy diffed files to {self.arch_dir}")
|
||||
for file in get_path("{CPP_TRANSLATOR_DIFF_OUT_DIR}").iterdir():
|
||||
self.copy_files(file, self.arch_dir)
|
||||
i += 1
|
||||
log.info(f"Copied {i} files")
|
||||
|
||||
# MC tests
|
||||
i = 0
|
||||
mc_dir = get_path("{MC_DIR}").joinpath(self.arch_dir_name)
|
||||
log.info(f"Copy MC test files to {mc_dir}")
|
||||
for file in get_path("{MCUPDATER_OUT_DIR}").iterdir():
|
||||
self.copy_files(file, mc_dir)
|
||||
i += 1
|
||||
legacy_mc_dir = get_path("{LEGACY_MC_DIR}").joinpath(self.arch_dir_name)
|
||||
for file in get_path("{MCUPDATER_OUT_FUZZ_DIR}").iterdir():
|
||||
self.copy_files(file, legacy_mc_dir)
|
||||
i += 1
|
||||
log.info(f"Copied {i} files")
|
||||
|
||||
exit(0)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="Auto-Sync-Updater",
|
||||
description="Capstones architecture module updater.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
dest="arch",
|
||||
help="Name of target architecture.",
|
||||
choices=ARCH_LLVM_NAMING,
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
dest="no_clean",
|
||||
help="Don't clean build dir before updating.",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-w",
|
||||
dest="write",
|
||||
help="Write generated/translated files to arch/<ARCH>/",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
dest="verbosity",
|
||||
help="Verbosity of the log messages.",
|
||||
choices=["debug", "info", "warning", "fatal"],
|
||||
default="info",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
dest="no_auto_apply",
|
||||
help="Differ: Do not apply saved diff resolutions. Ask for every diff again.",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
dest="steps",
|
||||
help="List of update steps to perform. If omitted, it performs all update steps.",
|
||||
choices=[
|
||||
"All",
|
||||
"IncGen",
|
||||
"Translate",
|
||||
"Diff",
|
||||
"MCUpdate",
|
||||
"PatchArchHeader",
|
||||
],
|
||||
nargs="+",
|
||||
default=["All"],
|
||||
)
|
||||
parser.add_argument(
|
||||
"--inc-list",
|
||||
dest="inc_list",
|
||||
help="Only generate the following inc files.",
|
||||
choices=[
|
||||
"All",
|
||||
"Disassembler",
|
||||
"AsmWriter",
|
||||
"RegisterInfo",
|
||||
"InstrInfo",
|
||||
"SubtargetInfo",
|
||||
"Mapping",
|
||||
"SystemOperand",
|
||||
],
|
||||
nargs="+",
|
||||
type=str,
|
||||
default=["All"],
|
||||
)
|
||||
parser.add_argument(
|
||||
"--copy-translated",
|
||||
dest="copy_translated",
|
||||
help="Copy the translated files and not the files produced by the Differ.",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ci",
|
||||
dest="wait_for_user",
|
||||
help="The translator will not wait for user input when printing important logs.",
|
||||
action="store_false",
|
||||
)
|
||||
arguments = parser.parse_args()
|
||||
return arguments
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
log.basicConfig(
|
||||
level=convert_loglevel(args.verbosity),
|
||||
stream=sys.stdout,
|
||||
format="%(levelname)-5s - %(message)s",
|
||||
force=True,
|
||||
)
|
||||
|
||||
Updater = ASUpdater(
|
||||
args.arch,
|
||||
args.write,
|
||||
args.steps,
|
||||
args.inc_list,
|
||||
args.no_clean,
|
||||
args.copy_translated,
|
||||
args.no_auto_apply,
|
||||
args.wait_for_user,
|
||||
)
|
||||
Updater.update()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,352 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import argparse
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
AARCH64_CC_MACROS = [
|
||||
"\n",
|
||||
"#define arm64_cc AArch64CC_CondCode\n",
|
||||
"#define ARM64_CC_EQ AArch64CC_EQ\n",
|
||||
"#define ARM64_CC_NE AArch64CC_NE\n",
|
||||
"#define ARM64_CC_HS AArch64CC_HS\n",
|
||||
"#define ARM64_CC_LO AArch64CC_LO\n",
|
||||
"#define ARM64_CC_MI AArch64CC_MI\n",
|
||||
"#define ARM64_CC_PL AArch64CC_PL\n",
|
||||
"#define ARM64_CC_VS AArch64CC_VS\n",
|
||||
"#define ARM64_CC_VC AArch64CC_VC\n",
|
||||
"#define ARM64_CC_HI AArch64CC_HI\n",
|
||||
"#define ARM64_CC_LS AArch64CC_LS\n",
|
||||
"#define ARM64_CC_GE AArch64CC_GE\n",
|
||||
"#define ARM64_CC_LT AArch64CC_LT\n",
|
||||
"#define ARM64_CC_GT AArch64CC_GT\n",
|
||||
"#define ARM64_CC_LE AArch64CC_LE\n",
|
||||
"#define ARM64_CC_AL AArch64CC_AL\n",
|
||||
"#define ARM64_CC_NV AArch64CC_NV\n",
|
||||
"#define ARM64_CC_INVALID AArch64CC_Invalid\n",
|
||||
"#define ARM64_VAS_INVALID AARCH64LAYOUT_INVALID\n",
|
||||
"#define ARM64_VAS_16B AARCH64LAYOUT_VL_16B\n",
|
||||
"#define ARM64_VAS_8B AARCH64LAYOUT_VL_8B\n",
|
||||
"#define ARM64_VAS_4B AARCH64LAYOUT_VL_4B\n",
|
||||
"#define ARM64_VAS_1B AARCH64LAYOUT_VL_1B\n",
|
||||
"#define ARM64_VAS_8H AARCH64LAYOUT_VL_8H\n",
|
||||
"#define ARM64_VAS_4H AARCH64LAYOUT_VL_4H\n",
|
||||
"#define ARM64_VAS_2H AARCH64LAYOUT_VL_2H\n",
|
||||
"#define ARM64_VAS_1H AARCH64LAYOUT_VL_1H\n",
|
||||
"#define ARM64_VAS_4S AARCH64LAYOUT_VL_4S\n",
|
||||
"#define ARM64_VAS_2S AARCH64LAYOUT_VL_2S\n",
|
||||
"#define ARM64_VAS_1S AARCH64LAYOUT_VL_1S\n",
|
||||
"#define ARM64_VAS_2D AARCH64LAYOUT_VL_2D\n",
|
||||
"#define ARM64_VAS_1D AARCH64LAYOUT_VL_1D\n",
|
||||
"#define ARM64_VAS_1Q AARCH64LAYOUT_VL_1Q\n",
|
||||
"#define arm64_vas AArch64Layout_VectorLayout\n",
|
||||
]
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="PatchHeaders",
|
||||
description="Patches generated enums into the main arch header file.",
|
||||
)
|
||||
parser.add_argument("--header", dest="header", help="Path header file.", type=Path)
|
||||
parser.add_argument("--inc", dest="inc", help="Path inc file.", type=Path)
|
||||
parser.add_argument(
|
||||
"--v6", dest="v6", help="aarch64.h/systemz.h header file location", type=Path
|
||||
)
|
||||
parser.add_argument(
|
||||
"--v5", dest="v5", help="arm64.h/systemz_v5.h header file location", type=Path
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c", dest="compat", help="Generate compatibility header", action="store_true"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p", dest="patch", help="Patch inc file into header", action="store_true"
|
||||
)
|
||||
arguments = parser.parse_args()
|
||||
return arguments
|
||||
|
||||
|
||||
def error_exit(msg: str) -> None:
|
||||
log.fatal(f"{msg}")
|
||||
exit(1)
|
||||
|
||||
|
||||
class HeaderPatcher:
|
||||
def __init__(self, header: Path, inc: Path, write_file: bool = True) -> None:
|
||||
self.header = header
|
||||
self.inc = inc
|
||||
self.inc_content: str = ""
|
||||
self.write_file = write_file
|
||||
# Gets set to the patched file content if writing to the file is disabled.
|
||||
self.patched_header_content: str = ""
|
||||
|
||||
def patch_header(self) -> bool:
|
||||
if not (self.header.exists() or self.header.is_file()):
|
||||
error_exit(f"self.header file {self.header.name} does not exist.")
|
||||
|
||||
if not (self.inc.exists() or self.inc.is_file()):
|
||||
error_exit(f"self.inc file {self.inc.name} does not exist.")
|
||||
|
||||
with open(self.header) as f:
|
||||
header_content = f.read()
|
||||
|
||||
if self.inc.name not in header_content:
|
||||
log.debug(f"{self.inc.name} has no include comments in {self.header.name}")
|
||||
return False
|
||||
|
||||
with open(self.inc) as f:
|
||||
self.inc_content = f.read()
|
||||
|
||||
to_write: dict[str:str] = {}
|
||||
enum_vals_id = ""
|
||||
for line in self.inc_content.splitlines():
|
||||
# No comments and empty lines
|
||||
if "/*" == line[:2] or not line:
|
||||
continue
|
||||
|
||||
if "#ifdef" in line:
|
||||
enum_vals_id = line[7:].strip("\n")
|
||||
to_write[enum_vals_id] = ""
|
||||
elif "#endif" in line and not enum_vals_id == "NOTGIVEN":
|
||||
enum_vals_id = ""
|
||||
elif "#undef" in line:
|
||||
continue
|
||||
else:
|
||||
line = re.sub(r"^(\s+)?", "\t", line)
|
||||
if not enum_vals_id:
|
||||
enum_vals_id = "NOTGIVEN"
|
||||
to_write[enum_vals_id] = line + "\n"
|
||||
continue
|
||||
to_write[enum_vals_id] += line + "\n"
|
||||
for ev_id in to_write.keys():
|
||||
header_enum_id = f":{ev_id}" if ev_id != "NOTGIVEN" else ""
|
||||
regex = (
|
||||
rf"\s*// generated content <{self.inc.name}{header_enum_id}> begin.*(\n)"
|
||||
rf"(.*\n)*"
|
||||
rf"\s*// generated content <{self.inc.name}{header_enum_id}> end.*(\n)"
|
||||
)
|
||||
if not re.search(regex, header_content):
|
||||
error_exit(f"Could not locate include comments for {self.inc.name}")
|
||||
|
||||
new_content = (
|
||||
f"\n\t// generated content <{self.inc.name}{header_enum_id}> begin\n"
|
||||
+ "\t// clang-format off\n\n"
|
||||
+ to_write[ev_id]
|
||||
+ "\n\t// clang-format on\n"
|
||||
+ f"\t// generated content <{self.inc.name}{header_enum_id}> end\n"
|
||||
)
|
||||
|
||||
header_content = re.sub(regex, new_content, header_content)
|
||||
if self.write_file:
|
||||
with open(self.header, "w") as f:
|
||||
f.write(header_content)
|
||||
else:
|
||||
self.patched_header_content = header_content
|
||||
log.info(f"Patched {self.inc.name} into {self.header.name}")
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def file_in_main_header(header: Path, filename: str) -> bool:
|
||||
with open(header) as f:
|
||||
header_content = f.read()
|
||||
return filename in header_content
|
||||
|
||||
|
||||
class CompatHeaderBuilder:
|
||||
def __init__(self, v6: Path, v5: Path, arch: str):
|
||||
self.v6 = v6
|
||||
self.v5 = v5
|
||||
match arch:
|
||||
case "aarch64":
|
||||
self.v6_lower = "aarch64"
|
||||
self.v6_upper = "AARCH64"
|
||||
self.v6_camel = "AArch64"
|
||||
self.v5_lower = "arm64"
|
||||
self.v5_upper = "ARM64"
|
||||
case "systemz":
|
||||
self.v6_lower = "systemz"
|
||||
self.v6_upper = "SYSTEMZ"
|
||||
self.v6_camel = "SystemZ"
|
||||
self.v5_lower = "sysz"
|
||||
self.v5_upper = "SYSZ"
|
||||
case _:
|
||||
raise ValueError(f"{arch} not handled")
|
||||
|
||||
def replace_typedef_struct(self, v6_lines: list[str]) -> list[str]:
|
||||
output = list()
|
||||
typedef = ""
|
||||
for line in v6_lines:
|
||||
if typedef:
|
||||
if not re.search(r"^}\s[\w_]+;", line):
|
||||
# Skip struct content
|
||||
continue
|
||||
type_name = re.findall(r"[\w_]+", line)[0]
|
||||
output.append(
|
||||
f"typedef {type_name} {re.sub(self.v6_lower,self.v5_lower, type_name)};\n"
|
||||
)
|
||||
typedef = ""
|
||||
continue
|
||||
|
||||
if re.search(rf"^typedef\s+(struct|union)", line):
|
||||
typedef = line
|
||||
continue
|
||||
output.append(line)
|
||||
return output
|
||||
|
||||
def replace_typedef_enum(self, v6_lines: list[str]) -> list[str]:
|
||||
output = list()
|
||||
typedef = ""
|
||||
for line in v6_lines:
|
||||
if typedef:
|
||||
if not re.search(r"^}\s[\w_]+;", line):
|
||||
# Replace name
|
||||
if self.v6_camel not in line and self.v6_upper not in line:
|
||||
output.append(line)
|
||||
continue
|
||||
found = re.findall(
|
||||
rf"({self.v6_camel}|{self.v6_upper})([\w_]+)", line
|
||||
)
|
||||
entry_name: str = "".join(found[0])
|
||||
v5_name = entry_name.replace(self.v6_camel, self.v5_upper).replace(
|
||||
self.v6_upper, self.v5_upper
|
||||
)
|
||||
patched_line = re.sub(
|
||||
rf"({self.v6_camel}|{self.v6_upper}).+",
|
||||
f"{v5_name} = {entry_name},",
|
||||
line,
|
||||
)
|
||||
output.append(patched_line)
|
||||
continue
|
||||
# We still have LLVM and CS naming conventions mixed
|
||||
p = re.sub(self.v6_lower, self.v5_lower, line)
|
||||
p = re.sub(rf"({self.v6_camel}|{self.v6_upper})", self.v5_upper, p)
|
||||
output.append(p)
|
||||
typedef = ""
|
||||
continue
|
||||
|
||||
if re.search(rf"^typedef\s+enum", line):
|
||||
typedef = line
|
||||
output.append("typedef enum {\n")
|
||||
continue
|
||||
output.append(line)
|
||||
return output
|
||||
|
||||
def remove_comments(self, v6_lines: list[str]) -> list[str]:
|
||||
output = list()
|
||||
for line in v6_lines:
|
||||
if re.search(r"^\s*//", line) and "// SPDX" not in line:
|
||||
continue
|
||||
output.append(line)
|
||||
return output
|
||||
|
||||
def replace_v6_prefix(self, v6_lines: list[str]) -> list[str]:
|
||||
output = list()
|
||||
in_typedef = False
|
||||
for line in v6_lines:
|
||||
if "CAPSTONE_SYSTEMZ_COMPAT_HEADER" in line:
|
||||
output.append(line)
|
||||
if in_typedef:
|
||||
if re.search(r"^}\s[\w_]+;", line):
|
||||
in_typedef = False
|
||||
output.append(line)
|
||||
continue
|
||||
|
||||
if re.search(f"^typedef", line):
|
||||
in_typedef = True
|
||||
output.append(line)
|
||||
continue
|
||||
output.append(
|
||||
re.sub(rf"({self.v6_camel}|{self.v6_upper})", self.v5_upper, line)
|
||||
)
|
||||
return output
|
||||
|
||||
def replace_include_guards(self, v6_lines: list[str]) -> list[str]:
|
||||
output = list()
|
||||
skip = False
|
||||
for line in v6_lines:
|
||||
if "CAPSTONE_SYSTEMZ_COMPAT_HEADER" in line:
|
||||
# The compat heade is inlcuded in the v6 header.
|
||||
# Because v5 and v6 header share the same name.
|
||||
skip = True
|
||||
continue
|
||||
elif skip and "#endif" in line:
|
||||
skip = False
|
||||
continue
|
||||
elif skip:
|
||||
continue
|
||||
|
||||
if not re.search(r"^#(ifndef|define)", line):
|
||||
output.append(line)
|
||||
continue
|
||||
output.append(re.sub(self.v6_upper, self.v5_upper, line))
|
||||
return output
|
||||
|
||||
def inject_v6_header(self, v6_lines: list[str]) -> list[str]:
|
||||
output = list()
|
||||
header_inserted = False
|
||||
for line in v6_lines:
|
||||
if re.search(r"^#include", line):
|
||||
if not header_inserted:
|
||||
output.append(f'#include "{self.v6_lower}.h"\n')
|
||||
header_inserted = True
|
||||
output.append(line)
|
||||
return output
|
||||
|
||||
def add_cc_macros(self, v6_lines: list[str]) -> list[str]:
|
||||
v6_lines += AARCH64_CC_MACROS
|
||||
return v6_lines
|
||||
|
||||
def generate_v5_compat_header(self) -> bool:
|
||||
"""
|
||||
Translates the aarch64.h header into the arm64.h header and renames all aarch64 occurrences.
|
||||
It does simple regex matching and replacing.
|
||||
Same for systemz.h and SYSTEMZ -> SYSZ. But the output file is systemz_compatibility.h.
|
||||
"""
|
||||
log.info("Generate compatibility header")
|
||||
with open(self.v6) as f:
|
||||
v6_lines = f.readlines()
|
||||
|
||||
patched = self.replace_typedef_struct(v6_lines)
|
||||
patched = self.replace_typedef_enum(patched)
|
||||
patched = self.remove_comments(patched)
|
||||
patched = self.replace_v6_prefix(patched)
|
||||
patched = self.replace_include_guards(patched)
|
||||
patched = self.inject_v6_header(patched)
|
||||
if self.v6_lower == "aarch64":
|
||||
patched = self.add_cc_macros(patched)
|
||||
|
||||
with open(self.v5, "w+") as f:
|
||||
f.writelines(patched)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
if (not args.patch and not args.compat) or (args.patch and args.compat):
|
||||
print("You need to specify either -c or -p")
|
||||
exit(1)
|
||||
if args.compat and not (args.v6 and args.v5):
|
||||
print("Generating the v5 compatibility header requires --v5 and --v6")
|
||||
exit(1)
|
||||
if args.patch and not (args.inc and args.header):
|
||||
print("Patching headers requires --inc and --header")
|
||||
exit(1)
|
||||
|
||||
if args.patch:
|
||||
patcher = HeaderPatcher(args.header, args.inc)
|
||||
patcher.patch_header()
|
||||
exit(0)
|
||||
|
||||
if "aarch64" in args.v6.name:
|
||||
arch = "aarch64"
|
||||
elif "systemz" in args.v6.name:
|
||||
arch = "systemz"
|
||||
else:
|
||||
raise ValueError(f"Does not know the arch for header file: {args.v6.name}")
|
||||
|
||||
builder = CompatHeaderBuilder(args.v6, args.v5, arch)
|
||||
builder.generate_v5_compat_header()
|
||||
@@ -0,0 +1,170 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import hashlib
|
||||
import logging as log
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import termcolor
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.PathVarHandler import PathVarHandler
|
||||
|
||||
|
||||
def convert_loglevel(level: str) -> int:
|
||||
if level == "debug":
|
||||
return log.DEBUG
|
||||
elif level == "info":
|
||||
return log.INFO
|
||||
elif level == "warning":
|
||||
return log.WARNING
|
||||
elif level == "error":
|
||||
return log.ERROR
|
||||
elif level == "fatal":
|
||||
return log.FATAL
|
||||
elif level == "critical":
|
||||
return log.CRITICAL
|
||||
raise ValueError(f'Unknown loglevel "{level}"')
|
||||
|
||||
|
||||
def find_id_by_type(node: Node, node_types: [str], type_must_match: bool) -> bytes:
|
||||
"""
|
||||
Recursively searches for a node sequence with given node types.
|
||||
|
||||
A valid sequence is a path from node_n to node_{(n + |node_types|-1)} where
|
||||
forall i in {0, ..., |node_types|-1}: type(node_{(n + i)}) = node_types_i.
|
||||
|
||||
If a node sequence is found, this functions returns the text associated with the
|
||||
last node in the sequence.
|
||||
|
||||
:param node: Current node.
|
||||
:param node_types: List of node types.
|
||||
:param type_must_match: If true, it is mandatory for the current node that its type matches node_types[0]
|
||||
:return: The nodes text of the last node in a valid sequence of and empty string of no such sequence exists.
|
||||
"""
|
||||
if len(node_types) == 0:
|
||||
# No ids left to compare to: Nothing found
|
||||
return b""
|
||||
|
||||
# Set true if:
|
||||
# current node type matches.
|
||||
# OR
|
||||
# parent dictates that node type match
|
||||
type_must_match = node.type == node_types[0] or type_must_match
|
||||
if type_must_match and node.type != node_types[0]:
|
||||
# This child has no matching type. Return.
|
||||
return b""
|
||||
|
||||
if len(node_types) == 1 and type_must_match:
|
||||
if node.type == node_types[0]:
|
||||
# Found it
|
||||
return node.text
|
||||
else:
|
||||
# Not found. Return to parent
|
||||
return b""
|
||||
|
||||
# If this nodes type matches the first in the list
|
||||
# we remove this one from the list.
|
||||
# Otherwise, give the whole list to the child (since our type does not matter).
|
||||
children_id_types = node_types[1:] if type_must_match else node_types
|
||||
|
||||
# Check if any child has a matching type.
|
||||
for child in node.named_children:
|
||||
res = find_id_by_type(child, children_id_types, type_must_match)
|
||||
if res:
|
||||
# A path from this node matches the id_types!
|
||||
return res
|
||||
|
||||
# None of our children matched the type list.
|
||||
return b""
|
||||
|
||||
|
||||
def print_prominent_warning(msg: str, wait_for_user: bool = True) -> None:
|
||||
print("\n" + separator_line_1("yellow"))
|
||||
print(termcolor.colored("WARNING", "yellow", attrs=["bold"]) + "\n")
|
||||
print(msg)
|
||||
print(separator_line_1("yellow"))
|
||||
if wait_for_user:
|
||||
input("Press enter to continue...\n")
|
||||
|
||||
|
||||
def term_width() -> int:
|
||||
return shutil.get_terminal_size()[0]
|
||||
|
||||
|
||||
def print_prominent_info(msg: str, wait_for_user: bool = True) -> None:
|
||||
print("\n" + separator_line_1("blue"))
|
||||
print(msg)
|
||||
print(separator_line_1("blue"))
|
||||
if wait_for_user:
|
||||
input("Press enter to continue...\n")
|
||||
|
||||
|
||||
def bold(msg: str, color: str = None) -> str:
|
||||
if color:
|
||||
return termcolor.colored(msg, attrs=["bold"], color=color)
|
||||
return termcolor.colored(msg, attrs=["bold"])
|
||||
|
||||
|
||||
def colored(msg: str, color: str) -> str:
|
||||
return termcolor.colored(msg, color=color)
|
||||
|
||||
|
||||
def separator_line_1(color: str = None) -> str:
|
||||
return f"{bold(f'⎼' * int(term_width() / 2), color)}\n"
|
||||
|
||||
|
||||
def separator_line_2(color: str = None) -> str:
|
||||
return f"{bold(f'═' * int(term_width() / 2), color)}\n"
|
||||
|
||||
|
||||
def get_sha256(data: bytes) -> str:
|
||||
h = hashlib.sha256()
|
||||
h.update(data)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def get_header() -> str:
|
||||
return (
|
||||
"/* Capstone Disassembly Engine, http://www.capstone-engine.org */\n"
|
||||
"/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */\n"
|
||||
"/* Rot127 <unisono@quyllur.org> 2022-2023 */\n"
|
||||
"/* Automatically translated source file from LLVM. */\n\n"
|
||||
"/* LLVM-commit: <commit> */\n"
|
||||
"/* LLVM-tag: <tag> */\n\n"
|
||||
"/* Only small edits allowed. */\n"
|
||||
"/* For multiple similar edits, please create a Patch for the translator. */\n\n"
|
||||
"/* Capstone's C++ file translator: */\n"
|
||||
"/* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */\n\n"
|
||||
)
|
||||
|
||||
|
||||
def run_clang_format(out_paths: list[Path]):
|
||||
for out_file in out_paths:
|
||||
log.info(f"Format {out_file}")
|
||||
subprocess.run(
|
||||
[
|
||||
"clang-format",
|
||||
f"-style=file:{get_path('{CS_CLANG_FORMAT_FILE}')}",
|
||||
"-i",
|
||||
out_file,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def get_path(config_path: str) -> Path:
|
||||
return PathVarHandler().complete_path(config_path)
|
||||
|
||||
|
||||
def test_only_overwrite_path_var(var_name: str, new_path: Path):
|
||||
"""Don't use outside of testing."""
|
||||
return PathVarHandler().test_only_overwrite_var(var_name, new_path)
|
||||
|
||||
|
||||
def fail_exit(msg: str) -> None:
|
||||
"""Logs a fatal message and exits with error code 1."""
|
||||
log.fatal(msg)
|
||||
exit(1)
|
||||
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from autosync.Helper import fail_exit, get_path
|
||||
|
||||
|
||||
class IncGenerator:
|
||||
def __init__(self, arch: str, inc_list: list) -> None:
|
||||
self.arch: str = arch
|
||||
self.inc_list = inc_list # Names of inc files to generate.
|
||||
self.arch_dir_name: str = "PowerPC" if self.arch == "PPC" else self.arch
|
||||
self.patches_dir_path: Path = get_path("{INC_PATCH_DIR}")
|
||||
self.llvm_include_dir: Path = get_path("{LLVM_INCLUDE_DIR}")
|
||||
self.output_dir: Path = get_path("{BUILD_DIR}")
|
||||
self.llvm_target_dir: Path = get_path("{LLVM_TARGET_DIR}").joinpath(
|
||||
f"{self.arch_dir_name}"
|
||||
)
|
||||
self.llvm_tblgen: Path = get_path("{LLVM_TBLGEN_BIN}")
|
||||
self.output_dir_c_inc = get_path("{C_INC_OUT_DIR}")
|
||||
self.output_dir_cpp_inc = get_path("{CPP_INC_OUT_DIR}")
|
||||
with open(get_path("{INC_GEN_CONF_FILE}")) as f:
|
||||
self.conf = json.loads(f.read())
|
||||
self.check_paths()
|
||||
|
||||
def check_paths(self) -> None:
|
||||
if not self.llvm_include_dir.exists():
|
||||
fail_exit(f"{self.llvm_include_dir} does not exist.")
|
||||
if not self.llvm_target_dir.exists():
|
||||
fail_exit(f"{self.llvm_target_dir} does not exist.")
|
||||
if not self.llvm_tblgen.exists():
|
||||
fail_exit(f"{self.llvm_tblgen} does not exist. Have you build llvm-tblgen?")
|
||||
if not self.output_dir.exists():
|
||||
fail_exit(f"{self.output_dir} does not exist.")
|
||||
if not self.output_dir_c_inc.exists():
|
||||
log.debug(f"{self.output_dir_c_inc} does not exist. Creating it...")
|
||||
os.makedirs(self.output_dir_c_inc)
|
||||
if not self.output_dir_cpp_inc.exists():
|
||||
log.debug(f"{self.output_dir_cpp_inc} does not exist. Creating it...")
|
||||
os.makedirs(self.output_dir_cpp_inc)
|
||||
|
||||
def generate(self) -> None:
|
||||
self.gen_incs()
|
||||
self.move_mapping_files()
|
||||
|
||||
def move_mapping_files(self) -> None:
|
||||
"""
|
||||
Moves the <ARCH>GenCS files. They are written to CWD (I know, not nice).
|
||||
We move them manually to the build dir, as long as llvm-capstone doesn't
|
||||
allow to specify an output dir.
|
||||
"""
|
||||
for file in Path.cwd().iterdir():
|
||||
if re.search(rf"{self.arch}Gen.*\.inc", file.name):
|
||||
log.debug(f"Move {file} to {self.output_dir_c_inc}")
|
||||
if self.output_dir_c_inc.joinpath(file.name).exists():
|
||||
os.remove(self.output_dir_c_inc.joinpath(file.name))
|
||||
shutil.move(file, self.output_dir_c_inc)
|
||||
|
||||
if self.arch == "ARM":
|
||||
# We have to rename the file SystemOperand -> SystemRegister
|
||||
sys_ops_table_file = self.output_dir_c_inc.joinpath(
|
||||
"ARMGenSystemOperands.inc"
|
||||
)
|
||||
new_sys_ops_file = self.output_dir_c_inc.joinpath(
|
||||
"ARMGenSystemRegister.inc"
|
||||
)
|
||||
if "SystemOperand" not in self.inc_list:
|
||||
return
|
||||
elif not sys_ops_table_file.exists():
|
||||
fail_exit(
|
||||
f"{sys_ops_table_file} does not exist. But it should have been generated."
|
||||
)
|
||||
if new_sys_ops_file.exists():
|
||||
os.remove(new_sys_ops_file)
|
||||
shutil.move(sys_ops_table_file, new_sys_ops_file)
|
||||
|
||||
def gen_incs(self) -> None:
|
||||
for table in self.conf["inc_tables"]:
|
||||
if "All" not in self.inc_list and table["name"] not in self.inc_list:
|
||||
log.debug(f"Skip {table['name']} generation")
|
||||
continue
|
||||
|
||||
if table["only_arch"] and self.arch not in table["only_arch"]:
|
||||
continue
|
||||
|
||||
log.info(f"Generating {table['name']} tables...")
|
||||
for lang in table["lang"]:
|
||||
log.debug(f"Generating {lang} tables...")
|
||||
td_file = self.llvm_target_dir.joinpath(f"{self.arch}.td")
|
||||
out_file = f"{self.arch}Gen{table['inc_name']}.inc"
|
||||
if lang == "CCS":
|
||||
out_path = self.output_dir_c_inc.joinpath(out_file)
|
||||
elif lang == "C++":
|
||||
out_path = self.output_dir_cpp_inc.joinpath(out_file)
|
||||
else:
|
||||
raise NotImplementedError(f"{lang} not supported by llvm-tblgen.")
|
||||
|
||||
args = []
|
||||
args.append(str(self.llvm_tblgen))
|
||||
args.append(f"--printerLang={lang}")
|
||||
args.append(table["tblgen_arg"])
|
||||
args.append("-I")
|
||||
args.append(f"{str(self.llvm_include_dir)}")
|
||||
args.append("-I")
|
||||
args.append(f"{str(self.llvm_target_dir)}")
|
||||
if table["inc_name"]:
|
||||
args.append("-o")
|
||||
args.append(f"{str(out_path)}")
|
||||
args.append(str(td_file))
|
||||
|
||||
log.debug(" ".join(args))
|
||||
try:
|
||||
subprocess.run(
|
||||
args,
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log.fatal("Generation failed")
|
||||
raise e
|
||||
|
||||
def has_inc_patches(self) -> bool:
|
||||
patch_dir = self.patches_dir_path.joinpath(self.arch)
|
||||
return patch_dir.exists()
|
||||
|
||||
def apply_patches(self) -> None:
|
||||
"""
|
||||
Applies all patches of inc files.
|
||||
Files must be moved to their arch/<ARCH> directory before.
|
||||
"""
|
||||
patch_dir = self.patches_dir_path.joinpath(self.arch)
|
||||
if not patch_dir.exists():
|
||||
return
|
||||
|
||||
# apply patches in alphabetical order
|
||||
for patch in sorted(patch_dir.iterdir()):
|
||||
try:
|
||||
subprocess.run(
|
||||
["git", "apply", "-v", "--recount", str(patch)],
|
||||
check=True,
|
||||
)
|
||||
log.info(f"Applied inc patch {patch.name}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
log.warning(f".inc patch {patch.name} did not apply correctly!")
|
||||
log.warning(f"Error:\n{e.output}")
|
||||
@@ -0,0 +1,641 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import argparse
|
||||
import logging as log
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import subprocess as sp
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from autosync.Targets import TARGETS_LLVM_NAMING, TARGET_TO_DIR_NAME
|
||||
from autosync.Helper import convert_loglevel, get_path
|
||||
|
||||
|
||||
class LLVM_MC_Command:
|
||||
def __init__(self, cmd_line: str, mattr: str):
|
||||
self.cmd: str = ""
|
||||
self.opts: str = ""
|
||||
self.file: Path | None = None
|
||||
self.additional_mattr: str = mattr
|
||||
|
||||
self.cmd, self.opts, self.file = self.parse_llvm_mc_line(cmd_line)
|
||||
if not (self.cmd and self.opts and self.file):
|
||||
log.warning(f"Could not parse llvm-mc command: {cmd_line}")
|
||||
elif not "--show-encoding" in self.cmd:
|
||||
self.cmd = re.sub("llvm-mc", "llvm-mc --show-encoding", self.cmd)
|
||||
elif not "--disassemble" in self.cmd:
|
||||
self.cmd = re.sub("llvm-mc", "llvm-mc --disassemble", self.cmd)
|
||||
|
||||
def parse_llvm_mc_line(self, line: str) -> tuple[str, str, Path]:
|
||||
test_file_base_dir = str(get_path("{LLVM_LIT_TEST_DIR}").absolute())
|
||||
file = re.findall(rf"{test_file_base_dir}\S+", line)
|
||||
if not file:
|
||||
log.warning(f"llvm-mc command doesn't contain a file: {line}")
|
||||
return None, None, None
|
||||
test_file = file[0]
|
||||
cmd = re.sub(rf"{test_file}", "", line).strip()
|
||||
cmd = re.sub(r"\s+", " ", cmd)
|
||||
arch = re.finditer(r"(triple|arch)[=\s](\S+)", cmd)
|
||||
mattr = re.finditer(r"(mattr|mcpu)[=\s](\S+)", cmd)
|
||||
opts = ",".join([m.group(2) for m in arch]) if arch else ""
|
||||
if mattr:
|
||||
opts += "" if not opts else ","
|
||||
processed_attr = list()
|
||||
for m in mattr:
|
||||
attribute = m.group(2).strip("+")
|
||||
processed_attr.append(attribute)
|
||||
opts += ",".join(processed_attr)
|
||||
return cmd, opts, Path(test_file)
|
||||
|
||||
def exec(self) -> sp.CompletedProcess:
|
||||
with open(self.file, "b+r") as f:
|
||||
content = f.read()
|
||||
if self.additional_mattr:
|
||||
# If mattr exists, patch it into the cmd
|
||||
if "mattr" in self.cmd:
|
||||
self.cmd = re.sub(
|
||||
r"mattr[=\s]+", f"mattr={self.additional_mattr} -mattr=", self.cmd
|
||||
)
|
||||
else:
|
||||
self.cmd = re.sub(
|
||||
r"llvm-mc", f"llvm-mc -mattr={self.additional_mattr}", self.cmd
|
||||
)
|
||||
|
||||
log.debug(f"Run: {self.cmd}")
|
||||
result = sp.run(self.cmd.split(" "), input=content, capture_output=True)
|
||||
return result
|
||||
|
||||
def get_opts_list(self) -> list[str]:
|
||||
opts = self.opts.strip().strip(",")
|
||||
opts = re.sub(r"[, ]+", ",", opts)
|
||||
return opts.split(",")
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.cmd} < {str(self.file.absolute())}"
|
||||
|
||||
|
||||
class MCTest:
|
||||
"""
|
||||
A single test. It can contain multiple decoded instruction for a given byte sequence.
|
||||
In general a MCTest always tests a sequence of instructions in a single .text segment.
|
||||
"""
|
||||
|
||||
def __init__(self, arch: str, opts: list[str], encoding: str, asm_text: str):
|
||||
self.arch = arch
|
||||
self.opts = opts
|
||||
self.encoding: list[str] = [encoding]
|
||||
self.asm_text: list[str] = [asm_text]
|
||||
|
||||
def extend(self, encoding: str, asm_text: str):
|
||||
self.encoding.append(encoding)
|
||||
self.asm_text.append(asm_text)
|
||||
|
||||
def get_legacy_mc_test_triple(self):
|
||||
"""
|
||||
Returns the legacy triple for the old MC test files:
|
||||
<ARCH>, <MODE>, None
|
||||
Should only be used to generate fuzzing tests.
|
||||
"""
|
||||
triple = "# "
|
||||
if self.arch.startswith("CS_ARCH"):
|
||||
triple += self.arch
|
||||
else:
|
||||
triple += f"CS_ARCH_{self.arch.upper()}"
|
||||
opts = "|".join([f'"{o}"' for o in self.opts if o.startswith("CS_MODE_")])
|
||||
if not opts:
|
||||
opts = "0"
|
||||
triple += f", {opts}, None"
|
||||
return triple
|
||||
|
||||
def fuzz_test_str(self):
|
||||
old_mc_tcase = ""
|
||||
for enc, asm_text in zip(self.encoding, self.asm_text):
|
||||
if old_mc_tcase:
|
||||
old_mc_tcase += "\n"
|
||||
encoding = re.sub(r"[\[\]]", "", enc)
|
||||
encoding = encoding.strip()
|
||||
encoding = re.sub(r"[\s,]+", ",", encoding)
|
||||
old_mc_tcase += f"{encoding} == {asm_text}"
|
||||
return old_mc_tcase
|
||||
|
||||
def __str__(self):
|
||||
encoding = ",".join(self.encoding)
|
||||
encoding = re.sub(r"[\[\]]", "", encoding)
|
||||
encoding = encoding.strip()
|
||||
encoding = re.sub(r"[\s,]+", ", ", encoding)
|
||||
yaml_tc = (
|
||||
" -\n"
|
||||
" input:\n"
|
||||
" bytes: [ <ENCODING> ]\n"
|
||||
' arch: "<ARCH>"\n'
|
||||
" options: [ <OPTIONS> ]\n"
|
||||
" expected:\n"
|
||||
" insns:\n"
|
||||
)
|
||||
template = " -\n asm_text: <ASM_TEXT>\n"
|
||||
insn_cases = ""
|
||||
for text in self.asm_text:
|
||||
insn_cases += template.replace("<ASM_TEXT>", f'"{text}"')
|
||||
|
||||
yaml_tc = yaml_tc.replace("<ENCODING>", encoding)
|
||||
yaml_tc = yaml_tc.replace("<ARCH>", f"CS_ARCH_{self.arch.upper()}")
|
||||
yaml_tc = yaml_tc.replace("<OPTIONS>", ", ".join([f'"{o}"' for o in self.opts]))
|
||||
yaml_tc += insn_cases
|
||||
return yaml_tc
|
||||
|
||||
|
||||
class TestFile:
|
||||
def __init__(
|
||||
self,
|
||||
arch: str,
|
||||
file_path: Path,
|
||||
opts: list[str] | None,
|
||||
mc_cmd: LLVM_MC_Command,
|
||||
unified_test_cases: bool,
|
||||
):
|
||||
self.arch: str = arch
|
||||
self.file_path: Path = file_path
|
||||
self.opts: list[str] = list() if not opts else opts
|
||||
self.mc_cmd: LLVM_MC_Command = mc_cmd
|
||||
# Indexed by .text section count
|
||||
self.tests: dict[int : list[MCTest]] = dict()
|
||||
|
||||
self.init_tests(unified_test_cases)
|
||||
|
||||
def init_tests(self, unified_test_cases: bool):
|
||||
mc_output = self.mc_cmd.exec()
|
||||
if mc_output.stderr and not mc_output.stdout:
|
||||
# We can still continue. We just ignore the failed cases.
|
||||
log.debug(f"llvm-mc cmd stderr: {mc_output.stderr}")
|
||||
log.debug(f"llvm-mc result: {mc_output}")
|
||||
text_section = 0 # Counts the .text sections
|
||||
asm_pat = f"(?P<asm_text>.+)"
|
||||
enc_pat = r"(\[?(?P<full_enc_string>(?P<enc_bytes>((0x[a-fA-F0-9]{1,2}[, ]{0,2}))+)[^, ]?)\]?)"
|
||||
|
||||
dups = []
|
||||
for line in mc_output.stdout.splitlines():
|
||||
line = line.decode("utf8")
|
||||
if ".text" in line:
|
||||
text_section += 1
|
||||
continue
|
||||
match = re.search(
|
||||
rf"^\s*{asm_pat}\s*(#|//|@|!|;)\s*encoding:\s*{enc_pat}", line
|
||||
)
|
||||
if not match:
|
||||
continue
|
||||
full_enc_string = match.group("full_enc_string")
|
||||
if not re.search(r"0x[a-fA-F0-9]{1,2}$", full_enc_string[:-1]):
|
||||
log.debug(f"Ignore because symbol injection is needed: {line}")
|
||||
# The encoding string contains symbol information of the form:
|
||||
# [0xc0,0xe0,A,A,A... or similar. We ignore these for now.
|
||||
continue
|
||||
enc_bytes = match.group("enc_bytes").strip()
|
||||
asm_text = match.group("asm_text").strip()
|
||||
asm_text = re.sub(r"\t+", " ", asm_text)
|
||||
asm_text = asm_text.strip()
|
||||
if not self.valid_byte_seq(enc_bytes):
|
||||
continue
|
||||
|
||||
if (enc_bytes + asm_text) in dups:
|
||||
continue
|
||||
|
||||
dups.append(enc_bytes + asm_text)
|
||||
if text_section in self.tests:
|
||||
if unified_test_cases:
|
||||
self.tests[text_section][0].extend(enc_bytes, asm_text)
|
||||
else:
|
||||
self.tests[text_section].append(
|
||||
MCTest(self.arch, self.opts, enc_bytes, asm_text)
|
||||
)
|
||||
else:
|
||||
self.tests[text_section] = [
|
||||
MCTest(self.arch, self.opts, enc_bytes, asm_text)
|
||||
]
|
||||
|
||||
def has_tests(self) -> bool:
|
||||
return len(self.tests) != 0
|
||||
|
||||
def get_cs_testfile_content(self, only_tests: bool) -> str:
|
||||
content = "\n" if only_tests else "test_cases:\n"
|
||||
for tl in self.tests.values():
|
||||
content += "\n".join([str(t) for t in tl])
|
||||
return content
|
||||
|
||||
def get_fuzz_test_file_content(self, only_tests: bool) -> str:
|
||||
content = ""
|
||||
for tl in self.tests.values():
|
||||
if not content:
|
||||
content = (
|
||||
"\n" if only_tests else tl[0].get_legacy_mc_test_triple() + "\n"
|
||||
)
|
||||
content += "\n".join([t.fuzz_test_str() for t in tl])
|
||||
return content
|
||||
|
||||
def num_test_cases(self) -> int:
|
||||
return len(self.tests)
|
||||
|
||||
def valid_byte_seq(self, enc_bytes):
|
||||
match self.arch:
|
||||
case "AArch64":
|
||||
# It always needs 4 bytes.
|
||||
# Otherwise it is likely a reloc or symbol test
|
||||
return enc_bytes.count("0x") == 4
|
||||
case _:
|
||||
return True
|
||||
|
||||
def get_multi_mode_filename(self) -> Path:
|
||||
filename = self.file_path.stem
|
||||
parent = self.file_path.parent
|
||||
prefix_less_opts = [re.sub(r"CS_(OPT|MODE)_", "", o).lower() for o in self.opts]
|
||||
detailed_name = f"{filename}_{'_'.join(prefix_less_opts)}.txt"
|
||||
detailed_name = re.sub(r"[+-]", "_", detailed_name)
|
||||
out_path = parent.joinpath(detailed_name)
|
||||
return Path(out_path)
|
||||
|
||||
def get_simple_filename(self) -> Path:
|
||||
return self.file_path
|
||||
|
||||
def __lt__(self, other) -> bool:
|
||||
return str(self.file_path) < str(other.file_path)
|
||||
|
||||
|
||||
def exists_and_is_dir(x):
|
||||
return x.exists() and x.is_dir()
|
||||
|
||||
|
||||
class MCUpdater:
|
||||
"""
|
||||
The MCUpdater parses all test files of the LLVM MC regression tests.
|
||||
Each of those LLVM files can contain several llvm-mc commands to run on the same file.
|
||||
Mostly this is done to test the same file with different CPU features enabled.
|
||||
So it can test different flavors of assembly etc.
|
||||
|
||||
In Capstone all modules enable always all CPU features (even if this is not
|
||||
possible in reality).
|
||||
Due to this we always parse all llvm-mc commands run on a test file, generate a TestFile
|
||||
object for each of it, but only write the last one of them to disk.
|
||||
Once https://github.com/capstone-engine/capstone/issues/1992 is resolved, we can
|
||||
write all variants of a test file to disk.
|
||||
|
||||
This is already implemented and tested with multi_mode = True.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
arch: str,
|
||||
mc_dir: Path,
|
||||
excluded: list[str] | None,
|
||||
included: list[str] | None,
|
||||
unified_test_cases: bool,
|
||||
multi_mode: bool = False,
|
||||
):
|
||||
self.symbolic_links = list()
|
||||
self.arch = arch
|
||||
self.arch_dir_name = TARGET_TO_DIR_NAME[self.arch]
|
||||
self.test_dir_link_prefix = f"test_dir_{arch}_"
|
||||
self.mc_dir = mc_dir
|
||||
self.excluded = excluded if excluded else list()
|
||||
self.included = included if included else list()
|
||||
self.test_files: list[TestFile] = list()
|
||||
self.unified_test_cases = unified_test_cases
|
||||
with open(get_path("{MCUPDATER_CONFIG_FILE}")) as f:
|
||||
self.conf = json.loads(f.read())
|
||||
# Additional mattr passed to llvm-mc
|
||||
self.mattr: str = (
|
||||
",".join(self.conf["additional_mattr"][self.arch])
|
||||
if self.arch in self.conf["additional_mattr"]
|
||||
else ""
|
||||
)
|
||||
# A list of options which are always added.
|
||||
self.mandatory_options: list[str] = (
|
||||
self.conf["mandatory_options"][self.arch]
|
||||
if self.arch in self.conf["mandatory_options"]
|
||||
else list()
|
||||
)
|
||||
self.default_endianess: str = (
|
||||
self.conf["default_endianess"][self.arch]
|
||||
if self.arch in self.conf["default_endianess"]
|
||||
else ""
|
||||
)
|
||||
self.remove_options: str = (
|
||||
self.conf["remove_options"][self.arch]
|
||||
if self.arch in self.conf["remove_options"]
|
||||
else list()
|
||||
)
|
||||
self.remove_options = [x.lower() for x in self.remove_options]
|
||||
self.replace_option_map: dict = (
|
||||
self.conf["replace_option_map"][self.arch]
|
||||
if self.arch in self.conf["replace_option_map"]
|
||||
else {}
|
||||
)
|
||||
self.replace_option_map = {
|
||||
k.lower(): v
|
||||
for k, v in self.replace_option_map.items()
|
||||
if k.lower not in self.remove_options
|
||||
}
|
||||
self.multi_mode = multi_mode
|
||||
|
||||
def check_prerequisites(self, paths):
|
||||
if all(not exists_and_is_dir(path) for path in paths):
|
||||
raise ValueError(
|
||||
f"'{paths}' does not exits or is not a directory. Cannot generate tests from there."
|
||||
)
|
||||
llvm_lit_cfg = get_path("{LLVM_LIT_TEST_DIR}")
|
||||
if not llvm_lit_cfg.exists():
|
||||
raise ValueError(
|
||||
f"Could not find '{llvm_lit_cfg}'. Check {{LLVM_LIT_TEST_DIR}} in path_vars.json."
|
||||
)
|
||||
|
||||
def write_to_build_dir(self, fuzzer_tests: bool = False):
|
||||
no_tests_file = 0
|
||||
file_cnt = 0
|
||||
test_cnt = 0
|
||||
overwritten = 0
|
||||
files_written = set()
|
||||
for test in sorted(self.test_files):
|
||||
if not test.has_tests():
|
||||
no_tests_file += 1
|
||||
continue
|
||||
file_cnt += 1
|
||||
test_cnt += test.num_test_cases()
|
||||
|
||||
if self.multi_mode:
|
||||
rel_path = str(
|
||||
test.get_multi_mode_filename().relative_to(
|
||||
get_path("{LLVM_LIT_TEST_DIR}")
|
||||
)
|
||||
)
|
||||
else:
|
||||
rel_path = str(
|
||||
test.get_simple_filename().relative_to(
|
||||
get_path("{LLVM_LIT_TEST_DIR}")
|
||||
)
|
||||
)
|
||||
|
||||
filename = re.sub(rf"{self.test_dir_link_prefix}\d+", ".", rel_path)
|
||||
if fuzzer_tests:
|
||||
filename = get_path("{MCUPDATER_OUT_FUZZ_DIR}").joinpath(
|
||||
f"{filename}.cs"
|
||||
)
|
||||
else:
|
||||
filename = get_path("{MCUPDATER_OUT_DIR}").joinpath(f"{filename}.yaml")
|
||||
|
||||
if filename in files_written:
|
||||
write_mode = "a"
|
||||
else:
|
||||
write_mode = "w+"
|
||||
filename.parent.mkdir(parents=True, exist_ok=True)
|
||||
if self.multi_mode and filename.exists():
|
||||
log.warning(
|
||||
f"The following file exists already: {filename}. This indicates a blind spot in testing."
|
||||
)
|
||||
overwritten += 1
|
||||
elif not self.multi_mode and filename.exists():
|
||||
log.debug(f"Overwrite: {filename}")
|
||||
overwritten += 1
|
||||
with open(filename, write_mode) as f:
|
||||
if fuzzer_tests:
|
||||
content = test.get_fuzz_test_file_content(
|
||||
only_tests=(write_mode == "a")
|
||||
)
|
||||
else:
|
||||
content = test.get_cs_testfile_content(
|
||||
only_tests=(write_mode == "a")
|
||||
)
|
||||
f.write(content)
|
||||
log.debug(f"Write {filename}")
|
||||
files_written.add(filename)
|
||||
print()
|
||||
log.info(
|
||||
f"Got {len(self.test_files)} {'fuzzing ' if fuzzer_tests else ''}test files.\n"
|
||||
f"\t\tProcessed {file_cnt} files with {test_cnt} test cases.\n"
|
||||
f"\t\tIgnored {no_tests_file} without tests.\n"
|
||||
f"\t\tGenerated {len(files_written)} files"
|
||||
)
|
||||
if overwritten > 0:
|
||||
log.warning(
|
||||
f"Overwrote {overwritten} test files with the same name.\n"
|
||||
f"These files contain instructions of several different cpu features.\n"
|
||||
f"You have to use multi-mode to write them into distinct files.\n"
|
||||
f"The current setting will only keep the last one written.\n"
|
||||
f"See also: https://github.com/capstone-engine/capstone/issues/1992\n"
|
||||
"If you already used multi-mode (default = yes), there might be a blind spot in testing."
|
||||
)
|
||||
|
||||
def build_test_options(self, options):
|
||||
new_options = [] + self.mandatory_options
|
||||
for opt in options:
|
||||
opt = opt.lower()
|
||||
if opt in self.remove_options:
|
||||
continue
|
||||
elif opt in self.replace_option_map:
|
||||
new_options.extend(self.replace_option_map[opt])
|
||||
else:
|
||||
new_options.append(opt)
|
||||
if (
|
||||
not any(
|
||||
[
|
||||
True
|
||||
for x in new_options
|
||||
if x in ["CS_MODE_BIG_ENDIAN", "CS_MODE_LITTLE_ENDIAN"]
|
||||
]
|
||||
)
|
||||
and self.default_endianess
|
||||
):
|
||||
new_options.append(self.default_endianess)
|
||||
return new_options
|
||||
|
||||
def build_test_files(self, mc_cmds: list[LLVM_MC_Command]) -> list[TestFile]:
|
||||
log.info("Build TestFile objects")
|
||||
test_files = list()
|
||||
n_all = len(mc_cmds)
|
||||
for i, mcc in enumerate(mc_cmds):
|
||||
print(f"{i + 1}/{n_all} {mcc.file.name}", flush=True, end="\r")
|
||||
opts = self.build_test_options(mcc.get_opts_list())
|
||||
test_files.append(
|
||||
TestFile(
|
||||
self.arch,
|
||||
mcc.file,
|
||||
opts,
|
||||
mcc,
|
||||
self.unified_test_cases,
|
||||
)
|
||||
)
|
||||
return test_files
|
||||
|
||||
def run_llvm_lit(self, paths: list[Path]) -> list[LLVM_MC_Command]:
|
||||
"""
|
||||
Calls llvm-lit with the given paths to the tests.
|
||||
It parses the llvm-lit commands to LLVM_MC_Commands.
|
||||
"""
|
||||
lit_cfg_dir = get_path("{LLVM_LIT_TEST_DIR}")
|
||||
llvm_lit_cfg = str(lit_cfg_dir.absolute())
|
||||
args = ["lit", "-v", "-a", llvm_lit_cfg]
|
||||
for i, p in enumerate(paths):
|
||||
slink = lit_cfg_dir.joinpath(f"{self.test_dir_link_prefix}{i}")
|
||||
self.symbolic_links.append(slink)
|
||||
log.debug(f"Create link: {slink} -> {p}")
|
||||
try:
|
||||
slink.symlink_to(p, target_is_directory=True)
|
||||
except FileExistsError as e:
|
||||
print("Failed: Link existed. Please delete it")
|
||||
raise e
|
||||
|
||||
log.info(f"Run lit: {' '.join(args)}")
|
||||
cmds = sp.run(args, capture_output=True)
|
||||
if cmds.stderr:
|
||||
raise ValueError(f"llvm-lit failed with {cmds.stderr}")
|
||||
return self.extract_llvm_mc_cmds(cmds.stdout.decode("utf8"))
|
||||
|
||||
def extract_llvm_mc_cmds(self, cmds: str) -> list[LLVM_MC_Command]:
|
||||
log.debug("Parsing llvm-mc commands")
|
||||
# Get only the RUN lines which have a show-encoding set.
|
||||
cmd_lines = cmds.splitlines()
|
||||
log.debug(f"NO FILTER: {cmd_lines}")
|
||||
matches = list(
|
||||
filter(
|
||||
lambda l: (
|
||||
l
|
||||
if re.search(r"^RUN.+(show-encoding|disassemble)[^|]+", l)
|
||||
else None
|
||||
),
|
||||
cmd_lines,
|
||||
)
|
||||
)
|
||||
log.debug(f"FILTER RUN: {' '.join(matches)}")
|
||||
# Don't add tests which are allowed to fail
|
||||
matches = list(
|
||||
filter(lambda m: None if re.search(r"not\s+llvm-mc", m) else m, matches)
|
||||
)
|
||||
log.debug(f"FILTER not llvm-mc: {' '.join(matches)}")
|
||||
# Skip object file tests
|
||||
matches = list(
|
||||
filter(lambda m: None if re.search(r"filetype=obj", m) else m, matches)
|
||||
)
|
||||
log.debug(f"FILTER filetype=obj-mc: {' '.join(matches)}")
|
||||
# Skip any relocation related tests.
|
||||
matches = filter(lambda m: None if re.search(r"reloc", m) else m, matches)
|
||||
# Remove 'RUN: at ...' prefix
|
||||
matches = map(lambda m: re.sub(r"^RUN: at line \d+: ", "", m), matches)
|
||||
# Remove redirection
|
||||
matches = map(lambda m: re.sub(r"\d>&\d", "", m), matches)
|
||||
# Remove unused arguments
|
||||
matches = map(lambda m: re.sub(r"-o\s?-", "", m), matches)
|
||||
# Remove redirection of stderr to a file
|
||||
matches = map(lambda m: re.sub(r"2>\s?\S+", "", m), matches)
|
||||
# Remove piping to FileCheck
|
||||
matches = map(lambda m: re.sub(r"\|\s*FileCheck\s+.+", "", m), matches)
|
||||
# Remove input stream
|
||||
matches = map(lambda m: re.sub(r"\s+<", "", m), matches)
|
||||
|
||||
all_cmds = list()
|
||||
for match in matches:
|
||||
if self.included and not any(
|
||||
re.search(x, match) is not None for x in self.included
|
||||
):
|
||||
continue
|
||||
if any(re.search(x, match) is not None for x in self.excluded):
|
||||
continue
|
||||
llvm_mc_cmd = LLVM_MC_Command(match, self.mattr)
|
||||
if not llvm_mc_cmd.cmd:
|
||||
# Invalid
|
||||
continue
|
||||
all_cmds.append(llvm_mc_cmd)
|
||||
log.debug(f"Added: {llvm_mc_cmd}")
|
||||
log.debug(f"Extracted {len(all_cmds)} llvm-mc commands")
|
||||
return all_cmds
|
||||
|
||||
def gen_all(self):
|
||||
log.info("Check prerequisites")
|
||||
test_paths = list()
|
||||
if self.arch in self.conf["use_assembly_tests"]:
|
||||
log.info(f"Add assembly tests for {self.arch}")
|
||||
test_paths.append(self.mc_dir.joinpath(self.arch))
|
||||
if self.arch not in self.conf["exclude_disassembly_tests"]:
|
||||
log.info(f"Add disassembly tests for {self.arch}")
|
||||
disas_tests = self.mc_dir.joinpath(f"Disassembler/{self.arch_dir_name}")
|
||||
test_paths.append(disas_tests)
|
||||
self.check_prerequisites(test_paths)
|
||||
log.info("Generate MC regression tests")
|
||||
llvm_mc_cmds = self.run_llvm_lit(
|
||||
[path for path in test_paths if exists_and_is_dir(path)]
|
||||
)
|
||||
log.info(f"Got {len(llvm_mc_cmds)} llvm-mc commands to run")
|
||||
self.test_files = self.build_test_files(llvm_mc_cmds)
|
||||
for slink in self.symbolic_links:
|
||||
log.debug(f"Unlink {slink}")
|
||||
slink.unlink()
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="Test file updater",
|
||||
description="Synchronizes test files with LLVM",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
dest="mc_dir",
|
||||
help=f"Path to the LLVM MC test files. Default: {get_path('{LLVM_MC_TEST_DIR}')}",
|
||||
default=get_path("{LLVM_MC_TEST_DIR}"),
|
||||
type=Path,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
dest="arch",
|
||||
help="Name of architecture to update.",
|
||||
choices=TARGETS_LLVM_NAMING,
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
dest="excluded_files",
|
||||
metavar="filename",
|
||||
nargs="+",
|
||||
help="File names to exclude from update (can be a regex pattern).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
dest="included_files",
|
||||
metavar="filename",
|
||||
nargs="+",
|
||||
help="Specific list of file names to update (can be a regex pattern).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-u",
|
||||
dest="unified_tests",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="If set, all instructions of a text segment will decoded and tested at once. Should be set, if instructions depend on each other.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
dest="verbosity",
|
||||
help="Verbosity of the log messages.",
|
||||
choices=["debug", "info", "warning", "fatal"],
|
||||
default="info",
|
||||
)
|
||||
arguments = parser.parse_args()
|
||||
return arguments
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
log.basicConfig(
|
||||
level=convert_loglevel(args.verbosity),
|
||||
stream=sys.stdout,
|
||||
format="%(levelname)-5s - %(message)s",
|
||||
force=True,
|
||||
)
|
||||
|
||||
MCUpdater(
|
||||
args.arch,
|
||||
args.mc_dir,
|
||||
args.excluded_files,
|
||||
args.included_files,
|
||||
args.unified_tests,
|
||||
True,
|
||||
).gen_all()
|
||||
@@ -0,0 +1,113 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import json
|
||||
import logging as log
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Singleton(type):
|
||||
_instances = {}
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
||||
return cls._instances[cls]
|
||||
|
||||
|
||||
class PathVarHandler(metaclass=Singleton):
|
||||
def __init__(self) -> None:
|
||||
try:
|
||||
res = subprocess.run(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
log.fatal("Could not get repository top level directory.")
|
||||
exit(1)
|
||||
repo_root = res.stdout.decode("utf8").strip("\n")
|
||||
# The main directories
|
||||
self.paths: dict[str:Path] = dict()
|
||||
self.paths["{CS_ROOT}"] = Path(repo_root)
|
||||
self.paths["{AUTO_SYNC_ROOT}"] = Path(repo_root).joinpath("suite/auto-sync/")
|
||||
self.paths["{AUTO_SYNC_SRC}"] = self.paths["{AUTO_SYNC_ROOT}"].joinpath(
|
||||
"src/autosync/"
|
||||
)
|
||||
path_config_file = self.paths["{AUTO_SYNC_SRC}"].joinpath("path_vars.json")
|
||||
|
||||
# Load variables
|
||||
with open(path_config_file) as f:
|
||||
vars = json.load(f)
|
||||
|
||||
paths = vars["paths"]
|
||||
self.create_during_runtime = vars["create_during_runtime"]
|
||||
|
||||
missing = list()
|
||||
for p_name, path in paths.items():
|
||||
resolved = path
|
||||
for var_id in re.findall(r"\{.+}", resolved):
|
||||
if var_id not in self.paths:
|
||||
log.fatal(
|
||||
f"{var_id} hasn't been added to the PathVarsHandler, yet. The var must be defined in a previous entry."
|
||||
)
|
||||
exit(1)
|
||||
resolved: str = re.sub(var_id, str(self.paths[var_id]), resolved)
|
||||
log.debug(f"Set {p_name} = {resolved}")
|
||||
if not Path(resolved).exists() and (
|
||||
p_name not in self.create_during_runtime
|
||||
and p_name not in vars["ignore_missing"]
|
||||
):
|
||||
missing.append(resolved)
|
||||
elif var_id in self.create_during_runtime:
|
||||
self.create_path(var_id, resolved)
|
||||
self.paths[p_name] = Path(resolved)
|
||||
if len(missing) > 0:
|
||||
log.fatal(f"Some paths from config file are missing!")
|
||||
for m in missing:
|
||||
log.fatal(f"\t{m}")
|
||||
exit(1)
|
||||
|
||||
def test_only_overwrite_var(self, var_name: str, new_path: Path):
|
||||
if var_name not in self.paths:
|
||||
raise ValueError(f"PathVarHandler doesn't have a path for '{var_name}'")
|
||||
if not new_path.exists():
|
||||
raise ValueError(f"New path doesn't exists: '{new_path}")
|
||||
self.paths[var_name] = new_path
|
||||
|
||||
def get_path(self, name: str) -> Path:
|
||||
if name not in self.paths:
|
||||
raise ValueError(f"Path variable {name} has no path saved.")
|
||||
if name in self.create_during_runtime:
|
||||
self.create_path(name, self.paths[name])
|
||||
return self.paths[name]
|
||||
|
||||
def complete_path(self, path_str: str) -> Path:
|
||||
resolved = path_str
|
||||
for p_name in re.findall(r"\{.+}", path_str):
|
||||
resolved = re.sub(p_name, str(self.get_path(p_name)), resolved)
|
||||
return Path(resolved)
|
||||
|
||||
@staticmethod
|
||||
def create_path(var_id: str, path: str):
|
||||
pp = Path(path)
|
||||
if pp.exists():
|
||||
return
|
||||
|
||||
log.debug(f"Create path {var_id} @ {path}")
|
||||
postfix = var_id.strip("}").split("_")[-1]
|
||||
if postfix == "FILE":
|
||||
if not pp.parent.exists():
|
||||
pp.parent.mkdir(parents=True)
|
||||
pp.touch()
|
||||
elif postfix == "DIR":
|
||||
pp.mkdir(parents=True)
|
||||
else:
|
||||
from autosync.Helper import fail_exit
|
||||
|
||||
fail_exit(
|
||||
f"The var_id: {var_id} must end in _FILE or _DIR. It ends in '{postfix}'"
|
||||
)
|
||||
@@ -0,0 +1,64 @@
|
||||
# Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
# Names of the target architectures as they are listed under llvm/lib/Target/
|
||||
TARGETS_LLVM_NAMING = [
|
||||
"ARM",
|
||||
"PowerPC",
|
||||
"Alpha",
|
||||
"AArch64",
|
||||
"LoongArch",
|
||||
"SystemZ",
|
||||
"Mips",
|
||||
"Xtensa",
|
||||
"TriCore",
|
||||
"ARC",
|
||||
"Sparc",
|
||||
]
|
||||
|
||||
# Names of the target architecture as they are used in code and pretty much everywhere else.
|
||||
ARCH_LLVM_NAMING = [
|
||||
"ARM",
|
||||
"PPC",
|
||||
"Alpha",
|
||||
"AArch64",
|
||||
"LoongArch",
|
||||
"SystemZ",
|
||||
"Mips",
|
||||
"Xtensa",
|
||||
"TriCore",
|
||||
"ARC",
|
||||
"Sparc",
|
||||
]
|
||||
|
||||
# Maps the target full name to the name used in code (and pretty much everywhere else).
|
||||
TARGET_TO_IN_CODE_NAME = {
|
||||
"ARM": "ARM",
|
||||
"PowerPC": "PPC",
|
||||
"Alpha": "Alpha",
|
||||
"AArch64": "AArch64",
|
||||
"LoongArch": "LoongArch",
|
||||
"SystemZ": "SystemZ",
|
||||
"Mips": "Mips",
|
||||
"Xtensa": "Xtensa",
|
||||
"TriCore": "TriCore",
|
||||
"ARC": "ARC",
|
||||
"Sparc": "Sparc",
|
||||
"ARCH": "ARCH", # For testing
|
||||
}
|
||||
|
||||
# Maps the name from ARCH_LLVM_NAMING to the directory name in LLVM
|
||||
TARGET_TO_DIR_NAME = {
|
||||
"ARM": "ARM",
|
||||
"PPC": "PowerPC",
|
||||
"Alpha": "Alpha",
|
||||
"AArch64": "AArch64",
|
||||
"LoongArch": "LoongArch",
|
||||
"SystemZ": "SystemZ",
|
||||
"Mips": "Mips",
|
||||
"Xtensa": "Xtensa",
|
||||
"TriCore": "TriCore",
|
||||
"ARC": "ARC",
|
||||
"Sparc": "Sparc",
|
||||
"ARCH": "ARCH", # For testing
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import json
|
||||
import logging as log
|
||||
from pathlib import Path
|
||||
|
||||
import tree_sitter_cpp as ts_cpp
|
||||
from tree_sitter import Language, Parser
|
||||
|
||||
from autosync.Helper import fail_exit
|
||||
|
||||
|
||||
class Configurator:
|
||||
"""
|
||||
Holds common setup procedures for the configuration.
|
||||
It reads the configuration file, compiles languages and initializes the Parser.
|
||||
"""
|
||||
|
||||
arch: str
|
||||
config_path: Path
|
||||
config: dict = None
|
||||
ts_cpp_lang: Language = None
|
||||
parser: Parser = None
|
||||
|
||||
def __init__(self, arch: str, config_path: Path) -> None:
|
||||
self.arch = arch
|
||||
self.config_path = config_path
|
||||
self.load_config()
|
||||
self.ts_set_cpp_language()
|
||||
self.init_parser()
|
||||
|
||||
def get_arch(self) -> str:
|
||||
return self.arch
|
||||
|
||||
def get_cpp_lang(self) -> Language:
|
||||
if self.ts_cpp_lang:
|
||||
return self.ts_cpp_lang
|
||||
self.ts_set_cpp_language()
|
||||
return self.ts_cpp_lang
|
||||
|
||||
def get_parser(self) -> Parser:
|
||||
if self.parser:
|
||||
return self.parser
|
||||
self.init_parser()
|
||||
return self.parser
|
||||
|
||||
def get_arch_config(self) -> dict:
|
||||
if self.config:
|
||||
return self.config[self.arch]
|
||||
self.load_config()
|
||||
return self.config[self.arch]
|
||||
|
||||
def get_general_config(self) -> dict:
|
||||
if self.config:
|
||||
return self.config["General"]
|
||||
self.load_config()
|
||||
return self.config["General"]
|
||||
|
||||
def get_patch_config(self) -> dict:
|
||||
if self.config:
|
||||
return self.config["General"]["patching"]
|
||||
self.load_config()
|
||||
return self.config["General"]["patching"]
|
||||
|
||||
def load_config(self) -> None:
|
||||
if not Path.exists(self.config_path):
|
||||
fail_exit(f"Could not load arch config file at '{self.config_path}'")
|
||||
with open(self.config_path) as f:
|
||||
conf = json.loads(f.read())
|
||||
if self.arch not in conf:
|
||||
fail_exit(
|
||||
f"{self.arch} has no configuration. Please add them in {self.config_path}!"
|
||||
)
|
||||
self.config = conf
|
||||
|
||||
def ts_set_cpp_language(self) -> None:
|
||||
self.ts_cpp_lang = Language(ts_cpp.language())
|
||||
|
||||
def init_parser(self) -> None:
|
||||
log.debug("Init parser")
|
||||
self.parser = Parser(self.ts_cpp_lang)
|
||||
+551
@@ -0,0 +1,551 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import argparse
|
||||
import logging as log
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import termcolor
|
||||
from tree_sitter import Language, Node, Parser, Query, Tree
|
||||
|
||||
from autosync.cpptranslator.Configurator import Configurator
|
||||
from autosync.cpptranslator.patches.AddCSDetail import AddCSDetail
|
||||
from autosync.cpptranslator.patches.AddOperand import AddOperand
|
||||
from autosync.cpptranslator.patches.Assert import Assert
|
||||
from autosync.cpptranslator.patches.BitCastStdArray import BitCastStdArray
|
||||
from autosync.cpptranslator.patches.CheckDecoderStatus import CheckDecoderStatus
|
||||
from autosync.cpptranslator.patches.ClassConstructorDef import ClassConstructorDef
|
||||
from autosync.cpptranslator.patches.ClassesDef import ClassesDef
|
||||
from autosync.cpptranslator.patches.ConstMCInstParameter import ConstMCInstParameter
|
||||
from autosync.cpptranslator.patches.ConstMCOperand import ConstMCOperand
|
||||
from autosync.cpptranslator.patches.CppInitCast import CppInitCast
|
||||
from autosync.cpptranslator.patches.CreateOperand0 import CreateOperand0
|
||||
from autosync.cpptranslator.patches.CreateOperand1 import CreateOperand1
|
||||
from autosync.cpptranslator.patches.Data import Data
|
||||
from autosync.cpptranslator.patches.DeclarationInConditionClause import (
|
||||
DeclarationInConditionalClause,
|
||||
)
|
||||
from autosync.cpptranslator.patches.DecodeInstruction import DecodeInstruction
|
||||
from autosync.cpptranslator.patches.DecoderCast import DecoderCast
|
||||
from autosync.cpptranslator.patches.DecoderParameter import DecoderParameter
|
||||
from autosync.cpptranslator.patches.FallThrough import FallThrough
|
||||
from autosync.cpptranslator.patches.FeatureBits import FeatureBits
|
||||
from autosync.cpptranslator.patches.FeatureBitsDecl import FeatureBitsDecl
|
||||
from autosync.cpptranslator.patches.FieldFromInstr import FieldFromInstr
|
||||
from autosync.cpptranslator.patches.GetNumOperands import GetNumOperands
|
||||
from autosync.cpptranslator.patches.GetOpcode import GetOpcode
|
||||
from autosync.cpptranslator.patches.GetOperand import GetOperand
|
||||
from autosync.cpptranslator.patches.GetOperandRegImm import GetOperandRegImm
|
||||
from autosync.cpptranslator.patches.GetRegClass import GetRegClass
|
||||
from autosync.cpptranslator.patches.GetRegFromClass import GetRegFromClass
|
||||
from autosync.cpptranslator.patches.GetSubReg import GetSubReg
|
||||
from autosync.cpptranslator.patches.Includes import Includes
|
||||
from autosync.cpptranslator.patches.InlineToStaticInline import InlineToStaticInline
|
||||
from autosync.cpptranslator.patches.IsOptionalDef import IsOptionalDef
|
||||
from autosync.cpptranslator.patches.IsPredicate import IsPredicate
|
||||
from autosync.cpptranslator.patches.IsRegImm import IsOperandRegImm
|
||||
from autosync.cpptranslator.patches.LLVMFallThrough import LLVMFallThrough
|
||||
from autosync.cpptranslator.patches.LLVMunreachable import LLVMUnreachable
|
||||
from autosync.cpptranslator.patches.BadConditionCode import BadConditionCode
|
||||
from autosync.cpptranslator.patches.LLVM_DEBUG import LLVM_DEBUG
|
||||
from autosync.cpptranslator.patches.MethodToFunctions import MethodToFunction
|
||||
from autosync.cpptranslator.patches.MethodTypeQualifier import MethodTypeQualifier
|
||||
from autosync.cpptranslator.patches.NamespaceAnon import NamespaceAnon
|
||||
from autosync.cpptranslator.patches.NamespaceArch import NamespaceArch
|
||||
from autosync.cpptranslator.patches.NamespaceLLVM import NamespaceLLVM
|
||||
from autosync.cpptranslator.patches.OutStreamParam import OutStreamParam
|
||||
from autosync.cpptranslator.patches.Override import Override
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.patches.PredicateBlockFunctions import (
|
||||
PredicateBlockFunctions,
|
||||
)
|
||||
from autosync.cpptranslator.patches.PrintAnnotation import PrintAnnotation
|
||||
from autosync.cpptranslator.patches.PrintRegImmShift import PrintRegImmShift
|
||||
from autosync.cpptranslator.patches.QualifiedIdentifier import QualifiedIdentifier
|
||||
from autosync.cpptranslator.patches.ReferencesDecl import ReferencesDecl
|
||||
from autosync.cpptranslator.patches.RegClassContains import RegClassContains
|
||||
from autosync.cpptranslator.patches.SetOpcode import SetOpcode
|
||||
from autosync.cpptranslator.patches.SignExtend import SignExtend
|
||||
from autosync.cpptranslator.patches.Size import Size
|
||||
from autosync.cpptranslator.patches.SizeAssignments import SizeAssignment
|
||||
from autosync.cpptranslator.patches.STIArgument import STIArgument
|
||||
from autosync.cpptranslator.patches.STIFeatureBits import STIFeatureBits
|
||||
from autosync.cpptranslator.patches.STParameter import SubtargetInfoParam
|
||||
from autosync.cpptranslator.patches.StreamOperation import StreamOperations
|
||||
from autosync.cpptranslator.patches.TemplateDeclaration import TemplateDeclaration
|
||||
from autosync.cpptranslator.patches.TemplateDefinition import TemplateDefinition
|
||||
from autosync.cpptranslator.patches.TemplateParamDecl import TemplateParamDecl
|
||||
from autosync.cpptranslator.patches.TemplateRefs import TemplateRefs
|
||||
from autosync.cpptranslator.patches.UseMarkup import UseMarkup
|
||||
from autosync.cpptranslator.patches.UsingDeclaration import UsingDeclaration
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
from autosync.Helper import (
|
||||
convert_loglevel,
|
||||
get_header,
|
||||
get_path,
|
||||
print_prominent_warning,
|
||||
run_clang_format,
|
||||
)
|
||||
from autosync.cpptranslator.patches.isUInt import IsUInt
|
||||
from autosync.cpptranslator.tree_sitter_compatibility import query_captures_22_3
|
||||
|
||||
|
||||
class Translator:
|
||||
ts_cpp_lang: Language = None
|
||||
parser: Parser = None
|
||||
template_collector: TemplateCollector = None
|
||||
src_paths: [Path]
|
||||
out_paths: [Path]
|
||||
conf: dict
|
||||
src = b""
|
||||
current_src_path_in: Path = None
|
||||
current_src_path_out: Path = None
|
||||
tree: Tree = None
|
||||
|
||||
# Patch priorities: The bigger the number the later the patch will be applied.
|
||||
# Patches which create templates must always be executed last. Since syntax
|
||||
# in macros is no longer parsed as such (but is only recognized as macro body).
|
||||
#
|
||||
# If a patch must be executed before another patch (because the matching rules depend on it)
|
||||
# mark this dependency as you see below.
|
||||
patches: [Patch] = list()
|
||||
|
||||
patch_priorities: {str: int} = {
|
||||
RegClassContains.__name__: 0,
|
||||
GetRegClass.__name__: 0,
|
||||
GetRegFromClass.__name__: 0,
|
||||
CppInitCast.__name__: 0,
|
||||
BitCastStdArray.__name__: 0,
|
||||
PrintRegImmShift.__name__: 0,
|
||||
InlineToStaticInline.__name__: 0,
|
||||
GetSubReg.__name__: 0,
|
||||
UseMarkup.__name__: 0,
|
||||
ConstMCOperand.__name__: 0,
|
||||
ClassConstructorDef.__name__: 0,
|
||||
ConstMCInstParameter.__name__: 0,
|
||||
PrintAnnotation.__name__: 0,
|
||||
GetNumOperands.__name__: 0,
|
||||
STIArgument.__name__: 0,
|
||||
DecodeInstruction.__name__: 0,
|
||||
FallThrough.__name__: 0,
|
||||
SizeAssignment.__name__: 0,
|
||||
FieldFromInstr.__name__: 0,
|
||||
FeatureBitsDecl.__name__: 0,
|
||||
FeatureBits.__name__: 0,
|
||||
STIFeatureBits.__name__: 0,
|
||||
Includes.__name__: 0,
|
||||
CreateOperand0.__name__: 0, # ◁───┐ `CreateOperand0` removes most calls to MI.addOperand().
|
||||
AddOperand.__name__: 1, # ────────┘ The ones left are fixed with the `AddOperand` patch.
|
||||
CreateOperand1.__name__: 0,
|
||||
IsUInt.__name__: 0,
|
||||
GetOpcode.__name__: 0,
|
||||
SetOpcode.__name__: 0,
|
||||
GetOperand.__name__: 0,
|
||||
GetOperandRegImm.__name__: 0,
|
||||
IsOperandRegImm.__name__: 0,
|
||||
SignExtend.__name__: 0,
|
||||
DecoderParameter.__name__: 0,
|
||||
UsingDeclaration.__name__: 0,
|
||||
DecoderCast.__name__: 0,
|
||||
IsPredicate.__name__: 0,
|
||||
IsOptionalDef.__name__: 0,
|
||||
Assert.__name__: 0, # ◁─────────┐ The llvm_unreachable calls are replaced with asserts.
|
||||
LLVMUnreachable.__name__: 1, # ─┘ Those assert should stay.
|
||||
LLVMFallThrough.__name__: 0,
|
||||
BadConditionCode.__name__: 0,
|
||||
LLVM_DEBUG.__name__: 0,
|
||||
DeclarationInConditionalClause.__name__: 0,
|
||||
StreamOperations.__name__: 0,
|
||||
OutStreamParam.__name__: 0, # ◁──────┐ add_cs_detail() is added to printOperand functions with a certain
|
||||
SubtargetInfoParam.__name__: 0, # ◁──┤ signature. This signature depends on those patches.
|
||||
MethodToFunction.__name__: 0, # ◁────┤
|
||||
AddCSDetail.__name__: 1, # ──────────┘
|
||||
NamespaceAnon.__name__: 0, # ◁─────┐ "llvm" and anonymous namespaces must be removed first,
|
||||
NamespaceLLVM.__name__: 0, # ◁─────┤ so they don't match in NamespaceArch.
|
||||
NamespaceArch.__name__: 1, # ──────┘
|
||||
PredicateBlockFunctions.__name__: 0,
|
||||
Override.__name__: 0,
|
||||
Size.__name__: 0,
|
||||
Data.__name__: 0,
|
||||
ClassesDef.__name__: 0, # ◁────────┐ Declarations must be extracted first from the classes.
|
||||
MethodTypeQualifier.__name__: 1, # ┘
|
||||
# All previous patches can contain qualified identifiers (Ids with the "::" operator) in their search patterns.
|
||||
# After this patch they are removed.
|
||||
QualifiedIdentifier.__name__: 2,
|
||||
ReferencesDecl.__name__: 3, # ◁────┐
|
||||
CheckDecoderStatus.__name__: 4, # ─┘ Reference declarations must be removed first.
|
||||
TemplateParamDecl.__name__: 5,
|
||||
TemplateRefs.__name__: 5,
|
||||
# Template declarations are replaced with macros.
|
||||
# Those declarations are parsed as macro afterwards
|
||||
TemplateDeclaration.__name__: 5,
|
||||
# Template definitions are replaced with macros.
|
||||
# Those template functions are parsed as macro afterwards.
|
||||
TemplateDefinition.__name__: 6,
|
||||
}
|
||||
|
||||
def __init__(self, configure: Configurator, wait_for_user: bool = False):
|
||||
self.configurator = configure
|
||||
self.wait_for_user = wait_for_user
|
||||
self.arch = self.configurator.get_arch()
|
||||
self.conf = self.configurator.get_arch_config()
|
||||
self.conf_general = self.configurator.get_general_config()
|
||||
self.ts_cpp_lang = self.configurator.get_cpp_lang()
|
||||
self.parser = self.configurator.get_parser()
|
||||
|
||||
self.src_paths: [Path] = [
|
||||
get_path(sp["in"]) for sp in self.conf["files_to_translate"]
|
||||
]
|
||||
t_out_dir: Path = get_path("{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}")
|
||||
self.out_paths: [Path] = [
|
||||
t_out_dir.joinpath(sp["out"]) for sp in self.conf["files_to_translate"]
|
||||
]
|
||||
|
||||
self.collect_template_instances()
|
||||
self.init_patches()
|
||||
|
||||
def read_src_file(self, src_path: Path) -> None:
|
||||
"""Reads the file at src_path into self.src"""
|
||||
log.debug(f"Read {src_path}")
|
||||
if not Path.exists(src_path):
|
||||
log.fatal(f"Could not open the source file '{src_path}'")
|
||||
exit(1)
|
||||
with open(src_path) as f:
|
||||
self.src = bytes(f.read(), "utf8")
|
||||
|
||||
def init_patches(self):
|
||||
log.debug("Init patches")
|
||||
priorities = dict(
|
||||
sorted(self.patch_priorities.items(), key=lambda item: item[1])
|
||||
)
|
||||
for ptype, p in priorities.items():
|
||||
match ptype:
|
||||
case RegClassContains.__name__:
|
||||
patch = RegClassContains(p)
|
||||
case GetRegClass.__name__:
|
||||
patch = GetRegClass(p)
|
||||
case GetRegFromClass.__name__:
|
||||
patch = GetRegFromClass(p)
|
||||
case CppInitCast.__name__:
|
||||
patch = CppInitCast(p)
|
||||
case BitCastStdArray.__name__:
|
||||
patch = BitCastStdArray(p)
|
||||
case CheckDecoderStatus.__name__:
|
||||
patch = CheckDecoderStatus(p)
|
||||
case ReferencesDecl.__name__:
|
||||
patch = ReferencesDecl(p)
|
||||
case FieldFromInstr.__name__:
|
||||
patch = FieldFromInstr(p)
|
||||
case FeatureBitsDecl.__name__:
|
||||
patch = FeatureBitsDecl(p)
|
||||
case FeatureBits.__name__:
|
||||
patch = FeatureBits(p, bytes(self.arch, "utf8"))
|
||||
case STIFeatureBits.__name__:
|
||||
patch = STIFeatureBits(p, bytes(self.arch, "utf8"))
|
||||
case QualifiedIdentifier.__name__:
|
||||
patch = QualifiedIdentifier(p)
|
||||
case Includes.__name__:
|
||||
patch = Includes(p, self.arch)
|
||||
case ClassesDef.__name__:
|
||||
patch = ClassesDef(p)
|
||||
case CreateOperand0.__name__:
|
||||
patch = CreateOperand0(p)
|
||||
case CreateOperand1.__name__:
|
||||
patch = CreateOperand1(p)
|
||||
case IsUInt.__name__:
|
||||
patch = IsUInt(p)
|
||||
case GetOpcode.__name__:
|
||||
patch = GetOpcode(p)
|
||||
case SetOpcode.__name__:
|
||||
patch = SetOpcode(p)
|
||||
case GetOperand.__name__:
|
||||
patch = GetOperand(p)
|
||||
case SignExtend.__name__:
|
||||
patch = SignExtend(p)
|
||||
case TemplateDeclaration.__name__:
|
||||
patch = TemplateDeclaration(p, self.template_collector)
|
||||
case TemplateDefinition.__name__:
|
||||
patch = TemplateDefinition(p, self.template_collector)
|
||||
case DecoderParameter.__name__:
|
||||
patch = DecoderParameter(p)
|
||||
case TemplateRefs.__name__:
|
||||
patch = TemplateRefs(p)
|
||||
case TemplateParamDecl.__name__:
|
||||
patch = TemplateParamDecl(p)
|
||||
case MethodTypeQualifier.__name__:
|
||||
patch = MethodTypeQualifier(p)
|
||||
case UsingDeclaration.__name__:
|
||||
patch = UsingDeclaration(p)
|
||||
case NamespaceLLVM.__name__:
|
||||
patch = NamespaceLLVM(p)
|
||||
case DecoderCast.__name__:
|
||||
patch = DecoderCast(p)
|
||||
case IsPredicate.__name__:
|
||||
patch = IsPredicate(p)
|
||||
case IsOptionalDef.__name__:
|
||||
patch = IsOptionalDef(p)
|
||||
case Assert.__name__:
|
||||
patch = Assert(p)
|
||||
case LLVMFallThrough.__name__:
|
||||
patch = LLVMFallThrough(p)
|
||||
case BadConditionCode.__name__:
|
||||
patch = BadConditionCode(p)
|
||||
case DeclarationInConditionalClause.__name__:
|
||||
patch = DeclarationInConditionalClause(p)
|
||||
case OutStreamParam.__name__:
|
||||
patch = OutStreamParam(p)
|
||||
case MethodToFunction.__name__:
|
||||
patch = MethodToFunction(p)
|
||||
case GetOperandRegImm.__name__:
|
||||
patch = GetOperandRegImm(p)
|
||||
case StreamOperations.__name__:
|
||||
patch = StreamOperations(p)
|
||||
case SubtargetInfoParam.__name__:
|
||||
patch = SubtargetInfoParam(p)
|
||||
case SizeAssignment.__name__:
|
||||
patch = SizeAssignment(p)
|
||||
case NamespaceArch.__name__:
|
||||
patch = NamespaceArch(p)
|
||||
case NamespaceAnon.__name__:
|
||||
patch = NamespaceAnon(p)
|
||||
case PredicateBlockFunctions.__name__:
|
||||
patch = PredicateBlockFunctions(p)
|
||||
case FallThrough.__name__:
|
||||
patch = FallThrough(p)
|
||||
case DecodeInstruction.__name__:
|
||||
patch = DecodeInstruction(p)
|
||||
case STIArgument.__name__:
|
||||
patch = STIArgument(p)
|
||||
case GetNumOperands.__name__:
|
||||
patch = GetNumOperands(p)
|
||||
case AddOperand.__name__:
|
||||
patch = AddOperand(p)
|
||||
case PrintAnnotation.__name__:
|
||||
patch = PrintAnnotation(p)
|
||||
case ConstMCInstParameter.__name__:
|
||||
patch = ConstMCInstParameter(p)
|
||||
case LLVMUnreachable.__name__:
|
||||
patch = LLVMUnreachable(p)
|
||||
case LLVM_DEBUG.__name__:
|
||||
patch = LLVM_DEBUG(p)
|
||||
case ClassConstructorDef.__name__:
|
||||
patch = ClassConstructorDef(p)
|
||||
case ConstMCOperand.__name__:
|
||||
patch = ConstMCOperand(p)
|
||||
case UseMarkup.__name__:
|
||||
patch = UseMarkup(p)
|
||||
case GetSubReg.__name__:
|
||||
patch = GetSubReg(p)
|
||||
case InlineToStaticInline.__name__:
|
||||
patch = InlineToStaticInline(p)
|
||||
case AddCSDetail.__name__:
|
||||
patch = AddCSDetail(p, self.arch)
|
||||
case PrintRegImmShift.__name__:
|
||||
patch = PrintRegImmShift(p)
|
||||
case IsOperandRegImm.__name__:
|
||||
patch = IsOperandRegImm(p)
|
||||
case Override.__name__:
|
||||
patch = Override(p)
|
||||
case Size.__name__:
|
||||
patch = Size(p)
|
||||
case Data.__name__:
|
||||
patch = Data(p)
|
||||
case _:
|
||||
log.fatal(f"Patch type {ptype} not in Patch init routine.")
|
||||
exit(1)
|
||||
self.patches.append(patch)
|
||||
|
||||
def parse(self, src_path: Path) -> None:
|
||||
self.read_src_file(src_path)
|
||||
log.debug("Parse source code")
|
||||
self.tree = self.parser.parse(self.src)
|
||||
|
||||
def patch_src(self, p_list: [(bytes, Node)]) -> None:
|
||||
if len(p_list) == 0:
|
||||
return
|
||||
# Sort list of patches descending so the patches which are last in the file
|
||||
# get patched first. This way the indices of the code snippets before
|
||||
# don't change.
|
||||
patches = sorted(p_list, key=lambda x: x[1].start_byte, reverse=True)
|
||||
|
||||
new_src = b""
|
||||
patch: bytes
|
||||
node: Node
|
||||
for patch, node in patches:
|
||||
start_byte: int = node.start_byte
|
||||
old_end_byte: int = node.end_byte
|
||||
start_point: (int, int) = node.start_point
|
||||
old_end_point: (int, int) = node.end_point
|
||||
|
||||
new_src = self.src[:start_byte] + patch + self.src[old_end_byte:]
|
||||
self.src = new_src
|
||||
d = len(patch) - (old_end_byte - start_byte)
|
||||
self.tree.edit(
|
||||
start_byte=start_byte,
|
||||
old_end_byte=old_end_byte,
|
||||
new_end_byte=old_end_byte + d,
|
||||
start_point=start_point,
|
||||
old_end_point=old_end_point,
|
||||
new_end_point=(old_end_point[0], old_end_point[1] + d),
|
||||
)
|
||||
self.tree = self.parser.parse(new_src, self.tree)
|
||||
|
||||
def apply_patch(self, patch: Patch) -> bool:
|
||||
"""Tests if the given patch should be applied for the current architecture or file."""
|
||||
apply_only_to = self.configurator.get_patch_config()["apply_patch_only_to"]
|
||||
patch_name = patch.__class__.__name__
|
||||
if patch_name not in apply_only_to:
|
||||
# No constraints
|
||||
return True
|
||||
|
||||
file_constraints = apply_only_to[patch_name]
|
||||
if self.current_src_path_in.name in file_constraints["files"]:
|
||||
return True
|
||||
elif (
|
||||
re.search("InstPrinter.cpp", self.current_src_path_in.name)
|
||||
and patch_name == AddCSDetail.__name__
|
||||
):
|
||||
print_prominent_warning(
|
||||
(
|
||||
f"The AddCSDetail patch is not applied to {self.current_src_path_in.name}. "
|
||||
"Have you forgotten to add it to arch_config.json?"
|
||||
),
|
||||
False,
|
||||
)
|
||||
return False
|
||||
|
||||
def translate(self) -> None:
|
||||
for self.current_src_path_in, self.current_src_path_out in zip(
|
||||
self.src_paths, self.out_paths
|
||||
):
|
||||
log.info(f"Translate '{self.current_src_path_in}'")
|
||||
self.parse(self.current_src_path_in)
|
||||
patch: Patch
|
||||
for patch in self.patches:
|
||||
if not self.apply_patch(patch):
|
||||
log.debug(f"Skip patch {patch.__class__.__name__}")
|
||||
continue
|
||||
pattern: str = patch.get_search_pattern()
|
||||
|
||||
# Each patch has a capture which includes the whole subtree searched for.
|
||||
# Additionally, it can include captures within this subtree.
|
||||
# Here we bundle these captures together.
|
||||
query: Query = self.ts_cpp_lang.query(pattern)
|
||||
captures_bundle: [[(Node, str)]] = list()
|
||||
for q in query_captures_22_3(query, self.tree.root_node):
|
||||
if q[1] == patch.get_main_capture_name():
|
||||
# The main capture the patch is looking for.
|
||||
captures_bundle.append([q])
|
||||
else:
|
||||
# A capture which is part of the main capture.
|
||||
# Add it to the bundle.
|
||||
if len(captures_bundle) > 0:
|
||||
captures_bundle[-1].append(q)
|
||||
|
||||
log.debug(
|
||||
f"Patch {patch.__class__.__name__} (to patch: {len(captures_bundle)})."
|
||||
)
|
||||
|
||||
p_list: (bytes, Node) = list()
|
||||
cb: [(Node, str)]
|
||||
for cb in captures_bundle:
|
||||
patch_kwargs = self.get_patch_kwargs(patch)
|
||||
bytes_patch: bytes = patch.get_patch(cb, self.src, **patch_kwargs)
|
||||
p_list.append((bytes_patch, cb[0][0]))
|
||||
self.patch_src(p_list)
|
||||
if self.tree.root_node.type == "ERROR":
|
||||
log.fatal(
|
||||
f"Patch {patch.__class__.__name__} corrupts the tree for {self.current_src_path_in.name}!"
|
||||
)
|
||||
exit(1)
|
||||
log.info(f"Patched file at '{self.current_src_path_out}'")
|
||||
with open(self.current_src_path_out, "w") as f:
|
||||
f.write(get_header())
|
||||
f.write(self.src.decode("utf8"))
|
||||
run_clang_format(self.out_paths)
|
||||
|
||||
def collect_template_instances(self):
|
||||
search_paths = [get_path(p) for p in self.conf["files_for_template_search"]]
|
||||
temp_arg_deduction = [
|
||||
p.encode("utf8") for p in self.conf["templates_with_arg_deduction"]
|
||||
]
|
||||
self.template_collector = TemplateCollector(
|
||||
self.parser, self.ts_cpp_lang, search_paths, temp_arg_deduction
|
||||
)
|
||||
self.template_collector.collect()
|
||||
|
||||
def get_patch_kwargs(self, patch):
|
||||
default_kwargs = dict()
|
||||
default_kwargs["tree"] = self.tree
|
||||
default_kwargs["ts_cpp_lang"] = self.ts_cpp_lang
|
||||
if isinstance(patch, Includes) and self.current_src_path_in:
|
||||
default_kwargs["filename"] = self.current_src_path_in.name
|
||||
return default_kwargs
|
||||
|
||||
def remark_manual_files(self) -> None:
|
||||
manual_edited = self.conf["manually_edited_files"]
|
||||
msg = ""
|
||||
if len(manual_edited) > 0:
|
||||
msg += (
|
||||
termcolor.colored(
|
||||
"The following files are too complex to translate! Please check them by hand.",
|
||||
attrs=["bold"],
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
else:
|
||||
return
|
||||
for f in manual_edited:
|
||||
msg += get_path(f).name + "\n"
|
||||
print_prominent_warning(msg, self.wait_for_user)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="CppTranslator",
|
||||
description="Capstones C++ to C translator for LLVM source files",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
dest="arch",
|
||||
help="Name of target architecture.",
|
||||
choices=["ARM", "PPC", "AArch64", "Alpha"],
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
dest="verbosity",
|
||||
help="Verbosity of the log messages.",
|
||||
choices=["debug", "info", "warning", "fatal"],
|
||||
default="info",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
dest="config_path",
|
||||
help="Config file for architectures.",
|
||||
default="arch_config.json",
|
||||
type=Path,
|
||||
)
|
||||
arguments = parser.parse_args()
|
||||
return arguments
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not sys.hexversion >= 0x030B00F0:
|
||||
log.fatal("Python >= v3.11 required.")
|
||||
exit(1)
|
||||
|
||||
args = parse_args()
|
||||
log.basicConfig(
|
||||
level=convert_loglevel(args.verbosity),
|
||||
stream=sys.stdout,
|
||||
format="%(levelname)-5s - %(message)s",
|
||||
)
|
||||
configurator = Configurator(args.arch, args.config_path)
|
||||
translator = Translator(configurator)
|
||||
translator.translate()
|
||||
translator.remark_manual_files()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
||||
<!--
|
||||
Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
SPDX-License-Identifier: BSD-3
|
||||
-->
|
||||
|
||||
# C++ Translator
|
||||
|
||||
Capstone uses source files from LLVM to disassemble opcodes.
|
||||
Because LLVM is written in C++ we must translate those files to C.
|
||||
|
||||
The task of the `CppTranslator` is to do just that.
|
||||
The translation will not result in a completely correct C file! But it takes away most of the manual work.
|
||||
|
||||
## The configuration file
|
||||
|
||||
The configuration for each architecture is set in `arch_config.json`.
|
||||
|
||||
The config values have the following meaning:
|
||||
|
||||
- `General`: Settings valid for all architectures.
|
||||
- `diff_color_new`: Color in the `Differ` for translated content.
|
||||
- `diff_color_old`: Color in the `Differ` for old/current Capstone content.
|
||||
- `diff_color_saved`: Color in the `Differ` for saved content.
|
||||
- `diff_color_edited`: Color in the `Differ` for edited content.
|
||||
- `patch_editor`: Editor to open for patch editing.
|
||||
- `nodes_to_diff`: List of parse tree nodes which get diffed - *Mind the note below*.
|
||||
- `node_type`: The `type` of the node to be diffed.
|
||||
- `identifier_node_type`: Types of child nodes which identify the node during diffing (the identifier must be the same in the translated and the old file!). Types can be of the form `<parent-type>/<child type>`.
|
||||
- `<ARCH>`: Settings valid for a specific architecture
|
||||
- `files_to_translate`: A list of file paths to translate.
|
||||
- `in`: *Path* to a specific source file.
|
||||
- `out`: The *filename* of the translated file.
|
||||
- `files_for_template_search`: List of file paths to search for calls to template functions.
|
||||
- `manually_edite_files`: List of files which are too complicated to translate. The user will be warned about them.
|
||||
- `templates_with_arg_deduction`: Template functions which uses [argument deduction](https://en.cppreference.com/w/cpp/language/template_argument_deduction). Those templates are translated to normal functions, not macro definition.
|
||||
|
||||
_Note_:
|
||||
- To understand the `nodes_to_diff` setting, check out `Differ.py`.
|
||||
- Paths can contain `{AUTO_SYNC_ROOT}`, `{CS_ROOT}` and `{CPP_TRANSLATOR_ROOT}`.
|
||||
They are replaced with the absolute paths to those directories.
|
||||
|
||||
## Translation process
|
||||
|
||||
The translation process simply searches for certain syntax and patches it.
|
||||
|
||||
To allow searches for complicated patterns we parse the C++ file with Tree-sitter.
|
||||
Afterward we can use [pattern queries](https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries)
|
||||
to find our syntax we would like to patch.
|
||||
|
||||
Here is an overview of the procedure:
|
||||
|
||||
- First the source file is parsed with Tree-Sitter.
|
||||
- Afterward the translator iterates of a number of patches.
|
||||
|
||||
For each patch we do the following.
|
||||
|
||||
```
|
||||
|
||||
Translator Patch
|
||||
+---+
|
||||
| | +----+
|
||||
| | Request pattern to search for | |
|
||||
| | ----------------------------------> | |
|
||||
| | | |
|
||||
| | Return pattern | |
|
||||
| | <--------------------------------- | |
|
||||
| | | |
|
||||
| | ---+ | |
|
||||
| | | Find | |
|
||||
| | | captures | |
|
||||
| | | in src | |
|
||||
| | <--+ | |
|
||||
| | | |
|
||||
| | Return captures found | |
|
||||
| | ----------------------------------> | |
|
||||
| | | |
|
||||
| | +-- | |
|
||||
| | Use capture | | |
|
||||
| | info to | | |
|
||||
| | build new | | |
|
||||
| | syntax str | | |
|
||||
| | +-> | |
|
||||
| | | |
|
||||
| | Return new syntax string to patch | |
|
||||
| | <---------------------------------- | |
|
||||
| | | |
|
||||
| | ---+ | |
|
||||
| | | Replace old | |
|
||||
| | | with new syntax | |
|
||||
| | | at all occurrences | |
|
||||
| | | in the file. | |
|
||||
| | <--+ | |
|
||||
| | | |
|
||||
+---+ +----+
|
||||
```
|
||||
|
||||
## C++ Template translation
|
||||
|
||||
Most of the C++ syntax is simple to translate. But unfortunately the one exception are C++ templates.
|
||||
|
||||
Translating template functions and calls from C++ to C is tricky.
|
||||
Since each template has a number of actual implementations we do the following.
|
||||
|
||||
- A template function definition is translated into a C macro.
|
||||
- The template parameters get translated to the macro parameters.
|
||||
- To differentiate the C implementations, the functions follow the naming pattern `fcn_[template_param_0]_[template_param_1]()`
|
||||
|
||||
<hr>
|
||||
|
||||
**Example**
|
||||
|
||||
This C++ template function
|
||||
|
||||
```cpp
|
||||
template<unsigned X>
|
||||
void fcn() {
|
||||
unsigned a = X * 8;
|
||||
}
|
||||
```
|
||||
becomes
|
||||
```
|
||||
#define DEFINE_FCN(X) \
|
||||
void fcn ## _ ## X() { \
|
||||
unsigned a = X * 8; \
|
||||
}
|
||||
```
|
||||
To define an implementation where `X = 0` we do
|
||||
```
|
||||
DEFINE_FCN(0)
|
||||
```
|
||||
To call this implementation we call `fcn_0()`.
|
||||
|
||||
_(There is a special case when a template parameter is passed on to a template call. But this is explained in the code.)_
|
||||
<hr>
|
||||
|
||||
### Enumerate template instances
|
||||
|
||||
In our C++ code a template function can be called with different template parameters.
|
||||
For each of those calls we need to define a template implementation in C.
|
||||
|
||||
To do that we first scan source files for calls to template functions (`TemplateCollector.py` does this).
|
||||
For each unique call we check the parameter list.
|
||||
Knowing the parameter list we can now define a C function which uses exactly those parameters.
|
||||
For the definition we use a macro as above.
|
||||
|
||||
<hr>
|
||||
|
||||
**Example**
|
||||
|
||||
Within this C++ code we see two template function calls:
|
||||
|
||||
```cpp
|
||||
void main() {
|
||||
fcn<0>();
|
||||
fcn<4>();
|
||||
}
|
||||
```
|
||||
With the knowledge that once parameter `1` and once parameter `4` was passed to the template,
|
||||
we can define the implementations with the help of our `DEFINE_FCN` macro.
|
||||
```c
|
||||
DEFINE_FCN(0)
|
||||
DEFINE_FCN(4)
|
||||
```
|
||||
|
||||
Within the C code we can now call those with `fcn_0()` and `fcn_4()`.
|
||||
<hr>
|
||||
+346
@@ -0,0 +1,346 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from tree_sitter import Language, Node, Parser, Query
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.tree_sitter_compatibility import query_captures_22_3
|
||||
|
||||
|
||||
class TemplateRefInstance:
|
||||
"""
|
||||
Represents a concrete instance of a template function reference.
|
||||
E.g. DecodeT2Imm7<shift, 2>
|
||||
"""
|
||||
|
||||
name: bytes
|
||||
args: bytes
|
||||
args_list: list
|
||||
dependent_calls = list()
|
||||
|
||||
# Holds the indices of the caller template parameters which set the templ. parameters
|
||||
# of this TemplateCallInstance.
|
||||
# Structure: {caller_name: i, "self_i": k}
|
||||
#
|
||||
# Only used if this is an incomplete TemplateInstance
|
||||
# (parameters are set by the template parameters of the calling function).
|
||||
caller_param_indices: [{str: int}] = list()
|
||||
|
||||
def __init__(
|
||||
self, name: bytes, args: bytes, start_point, start_byte, end_point, end_byte
|
||||
):
|
||||
self.name = name
|
||||
self.args = args
|
||||
self.start_point = start_point
|
||||
self.start_byte = start_byte
|
||||
self.end_point = end_point
|
||||
self.end_byte = end_byte
|
||||
self.args_list = TemplateCollector.templ_params_to_list(args)
|
||||
self.templ_name = name + args
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
self.name == other.name
|
||||
and self.args == other.args
|
||||
and any(
|
||||
[
|
||||
a == b
|
||||
for a, b in zip(
|
||||
self.caller_param_indices, other.caller_param_indices
|
||||
)
|
||||
]
|
||||
)
|
||||
and self.start_byte == other.start_byte
|
||||
and self.start_point == other.start_point
|
||||
and self.end_byte == other.end_byte
|
||||
and self.end_point == other.end_point
|
||||
)
|
||||
|
||||
def set_dep_calls(self, deps: list):
|
||||
self.dependent_calls = deps
|
||||
|
||||
def get_c_name(self):
|
||||
return b"_".join([self.name] + self.args_list)
|
||||
|
||||
def get_args_for_decl(self) -> list[bytes]:
|
||||
"""Returns the list of arguments, but replaces all characters which
|
||||
can not be part of a C identifier with _
|
||||
"""
|
||||
args_list = [re.sub(b"'", b"", a) for a in self.args_list]
|
||||
return args_list
|
||||
|
||||
|
||||
class TemplateCollector:
|
||||
"""
|
||||
Searches through the given files for calls to template functions.
|
||||
And creates a list with concrete template instances.
|
||||
"""
|
||||
|
||||
# List of completed template instances indexed by their name.
|
||||
# One function can have multiple template instances. Depending on the template arguments
|
||||
template_refs: {bytes: [TemplateRefInstance]} = dict()
|
||||
# List of incomplete template instances indexed by the **function name they depend on**!
|
||||
incomplete_template_refs: {bytes: [TemplateRefInstance]} = dict()
|
||||
sources: [{str: bytes}] = list()
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ts_parser: Parser,
|
||||
ts_cpp: Language,
|
||||
searchable_files: [Path],
|
||||
temp_arg_deduction: [bytes],
|
||||
):
|
||||
self.parser = ts_parser
|
||||
self.lang_cpp = ts_cpp
|
||||
self.searchable_files = searchable_files
|
||||
self.templates_with_arg_deduction = temp_arg_deduction
|
||||
|
||||
def collect(self):
|
||||
self.read_files()
|
||||
for x in self.sources:
|
||||
path = x["path"]
|
||||
src = x["content"]
|
||||
log.debug(f"Search for template references in {path}")
|
||||
|
||||
tree = self.parser.parse(src)
|
||||
query: Query = self.lang_cpp.query(self.get_template_pattern())
|
||||
capture_bundles = self.get_capture_bundles(query, tree)
|
||||
|
||||
for cb in capture_bundles:
|
||||
templ_name: Node = cb[1][0]
|
||||
templ_args: Node = cb[2][0]
|
||||
name = get_text(src, templ_name.start_byte, templ_name.end_byte)
|
||||
args = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
||||
|
||||
ti = TemplateRefInstance(
|
||||
name,
|
||||
args,
|
||||
cb[0][0].start_point,
|
||||
cb[0][0].start_byte,
|
||||
cb[0][0].end_point,
|
||||
cb[0][0].end_byte,
|
||||
)
|
||||
|
||||
log.debug(
|
||||
f"Found new template ref: {name.decode('utf8')}{args.decode('utf8')}"
|
||||
)
|
||||
|
||||
if not self.contains_template_dependent_param(src, ti, cb[0]):
|
||||
if name not in self.template_refs:
|
||||
self.template_refs[name] = list()
|
||||
# The template function has no parameter which is part of a previous
|
||||
# template definition. So all template parameters are well-defined.
|
||||
# Add it to the well-defined list.
|
||||
if ti not in self.template_refs[name]:
|
||||
self.template_refs[name].append(ti)
|
||||
self.resolve_dependencies()
|
||||
|
||||
def resolve_dependencies(self):
|
||||
# Resolve dependencies of templates until nothing new was resolved.
|
||||
prev_len = 0
|
||||
while (
|
||||
len(self.incomplete_template_refs) > 0
|
||||
and len(self.incomplete_template_refs) != prev_len
|
||||
):
|
||||
# Dict with new template calls which were previously incomplete
|
||||
# because one or more parameters were unknown.
|
||||
new_completed_tcs: {str: list} = dict()
|
||||
tc_instance_list: [TemplateRefInstance]
|
||||
for caller_name, tc_instance_list in self.template_refs.items():
|
||||
# Check if this caller has a dependent template call.
|
||||
# In other words: If a template parameter of this caller is given
|
||||
# to another template call in the callers body.
|
||||
if caller_name not in self.incomplete_template_refs:
|
||||
# Not in the dependency list. Skip it.
|
||||
continue
|
||||
# For each configuration of template parameters we complete a template reference.
|
||||
for caller_template in tc_instance_list:
|
||||
incomplete_tc: TemplateRefInstance
|
||||
for incomplete_tc in self.incomplete_template_refs[caller_name]:
|
||||
new_tc: TemplateRefInstance = self.get_completed_tc(
|
||||
caller_template, incomplete_tc
|
||||
)
|
||||
callee_name = new_tc.name
|
||||
if callee_name not in new_completed_tcs:
|
||||
new_completed_tcs[callee_name] = list()
|
||||
if new_tc not in new_completed_tcs[callee_name]:
|
||||
new_completed_tcs[callee_name].append(new_tc)
|
||||
del self.incomplete_template_refs[caller_name]
|
||||
|
||||
for templ_name, tc_list in new_completed_tcs.items():
|
||||
if templ_name in self.template_refs:
|
||||
self.template_refs[templ_name] += tc_list
|
||||
else:
|
||||
self.template_refs[templ_name] = tc_list
|
||||
prev_len = len(self.incomplete_template_refs)
|
||||
if prev_len > 0:
|
||||
log.info(
|
||||
f"Unresolved template calls: {self.incomplete_template_refs.keys()}. Patch them by hand!"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_completed_tc(
|
||||
tc: TemplateRefInstance, itc: TemplateRefInstance
|
||||
) -> TemplateRefInstance:
|
||||
new_tc = TemplateRefInstance(
|
||||
itc.name,
|
||||
itc.args,
|
||||
itc.start_byte,
|
||||
itc.start_byte,
|
||||
itc.end_point,
|
||||
itc.end_byte,
|
||||
)
|
||||
for indices in itc.caller_param_indices:
|
||||
if tc.name not in indices:
|
||||
# Index of other caller function. Skip.
|
||||
continue
|
||||
caller_i = indices[tc.name]
|
||||
self_i = indices["self_i"]
|
||||
new_tc.args_list[self_i] = tc.args_list[caller_i]
|
||||
new_tc.args = TemplateCollector.list_to_templ_params(new_tc.args_list)
|
||||
new_tc.templ_name = new_tc.name + new_tc.args
|
||||
return new_tc
|
||||
|
||||
def contains_template_dependent_param(
|
||||
self, src, ti: TemplateRefInstance, parse_tree: (Node, str)
|
||||
) -> bool:
|
||||
"""Here we check if one of the template parameters of the given template call,
|
||||
is a parameter of the callers template definition.
|
||||
|
||||
Let's assume we find the template call `func_B<X>()`.
|
||||
Now look at the context `func_B<X>` is in:
|
||||
|
||||
template<X>
|
||||
void func_A() {
|
||||
func_B<X>(a)
|
||||
}
|
||||
|
||||
Since `X` is a template parameter of `func_A` we have to wait until we see a call
|
||||
to `func_A<X>` where `X` gets properly defined.
|
||||
|
||||
Until then we save the TemplateInstance of `func_B<X>` in a list of incomplete
|
||||
template calls and note that it depends on `func_A`.
|
||||
If later a call to function `func_A` is found (with a concrete value for `X`) we can add
|
||||
a concrete TemplateInstance of `func_B`.
|
||||
|
||||
:param: src The current source code to operate on.
|
||||
:param: ti The TemplateInstance for which to check dependencies.
|
||||
:param: parse_tree The parse tree of the template call.
|
||||
:return: True if a dependency was found. False otherwise.
|
||||
"""
|
||||
|
||||
# Search up to the function definition this call belongs to
|
||||
node: Node = parse_tree[0]
|
||||
while node.type != "function_definition":
|
||||
node = node.parent
|
||||
if not node.prev_named_sibling.type == "template_parameter_list":
|
||||
# Caller is a normal function definition.
|
||||
# Nothing to do here.
|
||||
return False
|
||||
|
||||
caller_fcn_id = node.named_children[2].named_children[0]
|
||||
caller_fcn_name = get_text(
|
||||
src, caller_fcn_id.start_byte, caller_fcn_id.end_byte
|
||||
)
|
||||
caller_templ_params = get_text(
|
||||
src, node.prev_sibling.start_byte, node.prev_sibling.end_byte
|
||||
)
|
||||
pl = TemplateCollector.templ_params_to_list(caller_templ_params)
|
||||
has_parameter_dependency = False
|
||||
for i, param in enumerate(pl):
|
||||
if param in ti.args_list:
|
||||
has_parameter_dependency = True
|
||||
ti.caller_param_indices.append(
|
||||
{caller_fcn_name: i, "self_i": ti.args_list.index(param)}
|
||||
)
|
||||
|
||||
if not has_parameter_dependency:
|
||||
return False
|
||||
|
||||
if caller_fcn_name not in self.incomplete_template_refs:
|
||||
self.incomplete_template_refs[caller_fcn_name] = list()
|
||||
if ti not in self.incomplete_template_refs[caller_fcn_name]:
|
||||
self.incomplete_template_refs[caller_fcn_name].append(ti)
|
||||
return True
|
||||
|
||||
def read_files(self):
|
||||
for sf in self.searchable_files:
|
||||
if not Path.exists(sf):
|
||||
log.fatal(f"TemplateCollector: Could not find '{sf}' for search.")
|
||||
exit(1)
|
||||
log.debug(f"TemplateCollector: Read {sf}")
|
||||
with open(sf) as f:
|
||||
file = {"path": sf, "content": bytes(f.read(), "utf8")}
|
||||
self.sources.append(file)
|
||||
|
||||
@staticmethod
|
||||
def get_capture_bundles(query, tree):
|
||||
captures_bundle: list[list[tuple[Node, str]]] = list()
|
||||
for q in query_captures_22_3(query, tree.root_node):
|
||||
if q[1] == "templ_ref":
|
||||
captures_bundle.append([q])
|
||||
else:
|
||||
captures_bundle[-1].append(q)
|
||||
return captures_bundle
|
||||
|
||||
@staticmethod
|
||||
def get_template_pattern():
|
||||
"""
|
||||
:return: A pattern which finds either a template function calls or references.
|
||||
"""
|
||||
return (
|
||||
"(template_function"
|
||||
" ((identifier) @name)"
|
||||
" ((template_argument_list) @templ_args)"
|
||||
") @templ_ref"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def templ_params_to_list(templ_params: bytes) -> list[bytes]:
|
||||
if not templ_params:
|
||||
return list()
|
||||
|
||||
params = templ_params.strip(b"<>").split(b",")
|
||||
params = [p.strip() for p in params]
|
||||
res = list()
|
||||
for p in params:
|
||||
if len(p.split(b" ")) == 2:
|
||||
# Typename specified for parameter. Remove it.
|
||||
# If it was more than one space, it is likely an operation like `size + 1`
|
||||
p = p.split(b" ")[1]
|
||||
# true and false get resolved to 1 and 0
|
||||
if p == "true":
|
||||
p = "1"
|
||||
elif p == "false":
|
||||
p = "0"
|
||||
res.append(p)
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def list_to_templ_params(temp_param_list: list) -> bytes:
|
||||
return b"<" + b", ".join(temp_param_list) + b">"
|
||||
|
||||
@staticmethod
|
||||
def get_macro_c_call(name: bytes, arg_param_list: [bytes], fcn_args: bytes = b""):
|
||||
res = b""
|
||||
fa = [name] + arg_param_list
|
||||
for x in fa[:-1]:
|
||||
res += b"CONCAT(" + x + b", "
|
||||
res += fa[-1]
|
||||
return res + (b")" * (len(fa) - 1)) + fcn_args
|
||||
|
||||
@staticmethod
|
||||
def log_missing_ref_and_exit(func_ref: bytes) -> None:
|
||||
log.fatal(
|
||||
f"Template collector has no reference for {func_ref}.\n\n"
|
||||
f"The possible reasons are:\n"
|
||||
"\t\t\t- Not all C++ source files which call this function are listed in the config.\n"
|
||||
"\t\t\t- You removed the C++ template syntax from the .td file for this function.\n"
|
||||
"\t\t\t- The function is a template with argument deduction and has no `template<...>` preamble. "
|
||||
"Add it in the config as exception in this case."
|
||||
)
|
||||
exit(1)
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
{
|
||||
"General": {
|
||||
"diff_color_new": "green",
|
||||
"diff_color_old": "light_blue",
|
||||
"diff_color_saved": "yellow",
|
||||
"diff_color_edited": "light_magenta",
|
||||
"patch_editor": "vim",
|
||||
"patching": {
|
||||
"apply_patch_only_to": {
|
||||
"AddCSDetail": {
|
||||
"files": [
|
||||
"ARMInstPrinter.cpp",
|
||||
"PPCInstPrinter.cpp",
|
||||
"AArch64InstPrinter.cpp",
|
||||
"LoongArchInstPrinter.cpp",
|
||||
"MipsInstPrinter.cpp",
|
||||
"SystemZInstPrinter.cpp",
|
||||
"XtensaInstPrinter.cpp",
|
||||
"SparcInstPrinter.cpp"
|
||||
]
|
||||
},
|
||||
"InlineToStaticInline": {
|
||||
"files": [
|
||||
"ARMAddressingModes.h"
|
||||
]
|
||||
},
|
||||
"PrintRegImmShift": {
|
||||
"files": [
|
||||
"ARMInstPrinter.cpp"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"nodes_to_diff": [
|
||||
{
|
||||
"node_type": "function_definition",
|
||||
"identifier_node_type": ["function_declarator/identifier"]
|
||||
},{
|
||||
"node_type": "preproc_function_def",
|
||||
"identifier_node_type": ["identifier"]
|
||||
},{
|
||||
"node_type": "preproc_include",
|
||||
"identifier_node_type": ["string_literal", "system_lib_string"]
|
||||
},{
|
||||
"node_type": "preproc_define",
|
||||
"identifier_node_type": ["identifier"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ARM": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp",
|
||||
"out": "ARMDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp",
|
||||
"out": "ARMInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.h",
|
||||
"out": "ARMInstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMAddressingModes.h",
|
||||
"out": "ARMAddressingModes.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARM/Utils/ARMBaseInfo.cpp",
|
||||
"out": "ARMBaseInfo.c"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/ARMGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/ARMGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": [
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARM/Utils/ARMBaseInfo.h"
|
||||
]
|
||||
},
|
||||
"PPC": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp",
|
||||
"out": "PPCDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp",
|
||||
"out": "PPCInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h",
|
||||
"out": "PPCMCTargetDesc.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.h",
|
||||
"out": "PPCPredicates.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/PPCGenDisassemblerTables.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [
|
||||
"decodeRegisterClass"
|
||||
],
|
||||
"manually_edited_files": [
|
||||
"{LLVM_ROOT}/llvm/lib/Target/PowerPC/PPCInstrInfo.h",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/PowerPC/PPCRegisterInfo.h"
|
||||
]
|
||||
},
|
||||
"AArch64": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp",
|
||||
"out": "AArch64Disassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp",
|
||||
"out": "AArch64InstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h",
|
||||
"out": "AArch64InstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h",
|
||||
"out": "AArch64AddressingModes.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp",
|
||||
"out": "AArch64BaseInfo.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h",
|
||||
"out": "AArch64BaseInfo.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/AArch64GenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/AArch64GenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [
|
||||
"printImmSVE",
|
||||
"printAMIndexedWB",
|
||||
"isSVECpyImm",
|
||||
"isSVEAddSubImm",
|
||||
"printVectorIndex"
|
||||
],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Alpha": {
|
||||
"files_to_translate": [],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/AlphaGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/AlphaGenAsmWriter.inc"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"LoongArch": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp",
|
||||
"out": "LoongArchDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.cpp",
|
||||
"out": "LoongArchInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.h",
|
||||
"out": "LoongArchInstPrinter.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/LoongArchGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/LoongArchGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/LoongArch/Disassembler/LoongArchDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/LoongArch/MCTargetDesc/LoongArchInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Mips": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp",
|
||||
"out": "MipsDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp",
|
||||
"out": "MipsInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.h",
|
||||
"out": "MipsInstPrinter.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/MipsGenDisassemblerTables.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/Mips/MCTargetDesc/MipsInstPrinter.cpp",
|
||||
"{CPP_INC_OUT_DIR}/MipsGenAsmWriter.inc"
|
||||
],
|
||||
"templates_with_arg_deduction": [
|
||||
"DecodeINSVE_DF",
|
||||
"DecodeDAHIDATIMMR6",
|
||||
"DecodeDAHIDATI",
|
||||
"DecodeAddiGroupBranch",
|
||||
"DecodePOP35GroupBranchMMR6",
|
||||
"DecodeDaddiGroupBranch",
|
||||
"DecodePOP37GroupBranchMMR6",
|
||||
"DecodePOP65GroupBranchMMR6",
|
||||
"DecodePOP75GroupBranchMMR6",
|
||||
"DecodeBlezlGroupBranch",
|
||||
"DecodeBgtzlGroupBranch",
|
||||
"DecodeBgtzGroupBranch",
|
||||
"DecodeBlezGroupBranch",
|
||||
"DecodeBgtzGroupBranchMMR6",
|
||||
"DecodeBlezGroupBranchMMR6",
|
||||
"DecodeDINS",
|
||||
"DecodeDEXT",
|
||||
"DecodeCRC",
|
||||
"isReg"
|
||||
],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"SystemZ": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp",
|
||||
"out": "SystemZDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinter.cpp",
|
||||
"out": "SystemZInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinter.h",
|
||||
"out": "SystemZInstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp",
|
||||
"out": "SystemZMCTargetDesc.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.h",
|
||||
"out": "SystemZMCTargetDesc.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/SystemZGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/SystemZGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/SystemZ/Disassembler/SystemZDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Xtensa": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp",
|
||||
"out": "XtensaDisassembler.c"
|
||||
},
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp",
|
||||
"out": "XtensaInstPrinter.c"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/XtensaGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/XtensaGenAsmWriter.inc"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"TriCore": {
|
||||
"files_to_translate": [],
|
||||
"files_for_template_search": [],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"ARC": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp",
|
||||
"out": "ARCDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp",
|
||||
"out": "ARCInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.h",
|
||||
"out": "ARCInstPrinter.h"
|
||||
},
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInfo.h",
|
||||
"out": "ARCInfo.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/ARCGenDisassemblerTables.inc",
|
||||
"{CPP_INC_OUT_DIR}/ARCGenAsmWriter.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARC/Disassembler/ARCDisassembler.cpp",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/ARC/MCTargetDesc/ARCInstPrinter.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
},
|
||||
"Sparc": {
|
||||
"files_to_translate": [
|
||||
{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp",
|
||||
"out": "SparcDisassembler.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp",
|
||||
"out": "SparcInstPrinter.c"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.h",
|
||||
"out": "SparcInstPrinter.h"
|
||||
},{
|
||||
"in": "{LLVM_ROOT}/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h",
|
||||
"out": "SparcMCTargetDesc.h"
|
||||
}
|
||||
],
|
||||
"files_for_template_search": [
|
||||
"{CPP_INC_OUT_DIR}/SparcGenDisassemblerTables.inc",
|
||||
"{LLVM_ROOT}/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp"
|
||||
],
|
||||
"templates_with_arg_deduction": [],
|
||||
"manually_edited_files": []
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import (
|
||||
get_MCInst_var_name,
|
||||
get_text,
|
||||
template_param_list_to_dict,
|
||||
)
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class AddCSDetail(Patch):
|
||||
"""
|
||||
Adds calls to `<ARCH>_add_cs_detail_<n>()` for printOperand functions in <ARCH>InstPrinter.c
|
||||
|
||||
Patch void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNo, SStream *O) {...}
|
||||
to void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNo, SStream *O) {
|
||||
<ARCH>_add_cs_detail_<n>(MI, ARM_OP_GROUP_ThumbLdrLabelOperand, ...);
|
||||
...
|
||||
}
|
||||
"""
|
||||
|
||||
# TODO Simply checking for the passed types would be so much nicer.
|
||||
# Parameter lists of printOperand() functions we need to add `<ARCH>_add_cs_detail_<n>()` to.
|
||||
# Spaces are removed, so we only need to check the letters.
|
||||
valid_param_lists = [
|
||||
b"(MCInst*MI,unsignedOpNum,SStream*O)", # Default printOperand parameters.
|
||||
b"(MCInst*MI,unsignedOpNo,SStream*O)", # ARM - printComplexRotationOp / PPC default
|
||||
b"(MCInst*MI,intopNum,SStream *O)", # Mips - printMemOperandEA and others
|
||||
b"(SStream*O,ARM_AM::ShiftOpcShOpc,unsignedShImm,boolgetUseMarkup())", # ARM - printRegImmShift
|
||||
b"(MCInst*MI,unsignedOpNo,SStream*O,constchar*Modifier)", # PPC - printPredicateOperand
|
||||
b"(MCInst*MI,uint64_tAddress,unsignedOpNo,SStream*O)", # PPC - printBranchOperand
|
||||
b"(MCInst*MI,intOpNum,SStream*O)", # SystemZ
|
||||
b"(MCInst*MI,intOpNum,SStream*O)", # Xtensa printOperand parameters.
|
||||
b"(MCInst*MI,intOpNum,SStream*OS)", # Xtensa printOperand parameters.
|
||||
b"(MCInst*MI,intopNum,SStream*O)", # Sparc printOperand parameters.
|
||||
]
|
||||
|
||||
def __init__(self, priority: int, arch: str):
|
||||
super().__init__(priority)
|
||||
self.arch = arch
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_definition"
|
||||
" (_)+"
|
||||
" (function_declarator"
|
||||
' ((identifier) @fcn_id (#match? @fcn_id "print.*"))'
|
||||
" ((parameter_list) @p_list)"
|
||||
" )"
|
||||
" (compound_statement) @comp_stmt"
|
||||
") @print_op"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "print_op"
|
||||
|
||||
def get_patch(
|
||||
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
|
||||
) -> bytes:
|
||||
fcn_def: Node = captures[0][0]
|
||||
params = captures[2][0]
|
||||
params = get_text(src, params.start_byte, params.end_byte)
|
||||
if re.sub(b"[\n \t]", b"", params) not in self.valid_param_lists:
|
||||
return get_text(src, fcn_def.start_byte, fcn_def.end_byte)
|
||||
|
||||
fcn_id = captures[1][0]
|
||||
fcn_id = get_text(src, fcn_id.start_byte, fcn_id.end_byte)
|
||||
|
||||
add_cs_detail = self.get_add_cs_detail(src, fcn_def, fcn_id, params)
|
||||
|
||||
comp = captures[3][0]
|
||||
comp = get_text(src, comp.start_byte, comp.end_byte)
|
||||
return (
|
||||
b"static inline void "
|
||||
+ fcn_id
|
||||
+ params
|
||||
+ b"{ "
|
||||
+ add_cs_detail
|
||||
+ comp.strip(b"{")
|
||||
)
|
||||
|
||||
def get_add_cs_detail(
|
||||
self, src: bytes, fcn_def: Node, fcn_id: bytes, params: bytes
|
||||
) -> bytes:
|
||||
op_group_enum = (
|
||||
self.arch.encode("utf8") + b"_OP_GROUP_" + fcn_id[5:]
|
||||
) # Remove "print" from function id
|
||||
|
||||
is_template = fcn_def.prev_sibling.type == "template_parameter_list"
|
||||
if b"OpNum" in params:
|
||||
op_num_var_name = b"OpNum"
|
||||
elif b"OpNo" in params:
|
||||
op_num_var_name = b"OpNo"
|
||||
elif b"opNum" in params:
|
||||
op_num_var_name = b"opNum"
|
||||
else:
|
||||
raise ValueError("OpNum parameter could not be identified.")
|
||||
|
||||
if not is_template and op_num_var_name in params:
|
||||
# Standard printOperand() parameters
|
||||
mcinst_var = get_MCInst_var_name(src, fcn_def)
|
||||
return (
|
||||
f"{self.arch}_add_cs_detail_0(".encode()
|
||||
+ mcinst_var
|
||||
+ b", "
|
||||
+ op_group_enum
|
||||
+ b", "
|
||||
+ op_num_var_name
|
||||
+ b");"
|
||||
)
|
||||
elif op_group_enum == b"ARM_OP_GROUP_RegImmShift":
|
||||
return (
|
||||
f"{self.arch}_add_cs_detail_1(MI, ".encode()
|
||||
+ op_group_enum
|
||||
+ b", ShOpc, ShImm);"
|
||||
)
|
||||
elif is_template and op_num_var_name in params:
|
||||
mcinst_var = get_MCInst_var_name(src, fcn_def)
|
||||
templ_p = template_param_list_to_dict(fcn_def.prev_sibling)
|
||||
cs_args = b""
|
||||
for tp in templ_p:
|
||||
op_group_enum = (
|
||||
b"CONCAT(" + op_group_enum + b", " + tp["identifier"] + b")"
|
||||
)
|
||||
cs_args += b", " + tp["identifier"]
|
||||
return (
|
||||
f"{self.arch}_add_cs_detail_{len(templ_p)}(".encode()
|
||||
+ mcinst_var
|
||||
+ b", "
|
||||
+ op_group_enum
|
||||
+ b", "
|
||||
+ op_num_var_name
|
||||
+ b" "
|
||||
+ cs_args
|
||||
+ b");"
|
||||
)
|
||||
log.fatal(f"Case {op_group_enum} not handled.")
|
||||
exit(1)
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class AddOperand(Patch):
|
||||
"""
|
||||
Patch MI.addOperand(...)
|
||||
to MCInst_addOperand(MI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "addOperand"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @add_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "add_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable name (MI, Inst)
|
||||
inst_var: Node = captures[1][0]
|
||||
# Arguments of getOperand(...)
|
||||
get_op_args = captures[3][0]
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, get_op_args.start_byte, get_op_args.end_byte)
|
||||
return b"MCInst_addOperand2(" + inst + b", " + args + b")"
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.patches.Helper import get_text_from_node
|
||||
|
||||
|
||||
class Assert(Patch):
|
||||
"""
|
||||
Patch replace `assert`|`report_fatal_error` with `CS_ASSERT`
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(expression_statement"
|
||||
" (call_expression"
|
||||
' ((identifier) @id (#match? @id "assert|report_fatal_error"))'
|
||||
" ((argument_list) @arg_list)"
|
||||
" )"
|
||||
") @assert"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "assert"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
args = get_text_from_node(src, captures[2][0])
|
||||
return b"CS_ASSERT" + args + b";"
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Copyright © 2024 Dmitry Sibitsev <sibirtsevdl@gmail.com>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class BadConditionCode(Patch):
|
||||
"""
|
||||
Patch return BadConditionCode
|
||||
to CS_ASSERT(0 && "Unknown condition code passed")
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(return_statement "
|
||||
" (call_expression "
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "BadConditionCode")'
|
||||
" (argument_list)"
|
||||
" )"
|
||||
") @bad_condition_code"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "bad_condition_code"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b'CS_ASSERT(0 && "Unknown condition code passed");'
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class BitCastStdArray(Patch):
|
||||
"""
|
||||
Patch auto S = bit_cast<std::array<int32_t, 2>>(Imm);
|
||||
to union {
|
||||
typeof(Imm) In;
|
||||
int32_t Out[2];
|
||||
} U_S;
|
||||
U_S.In = Imm;
|
||||
int32_t *S = U_S.Out;
|
||||
|
||||
MSVC doesn't support typeof so it has to be resolved manually.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(declaration"
|
||||
" (placeholder_type_specifier)"
|
||||
" (init_declarator"
|
||||
" (identifier) @arr_name"
|
||||
" (call_expression"
|
||||
" (template_function"
|
||||
' ((identifier) @tfid (#eq @tfid "bit_cast"))'
|
||||
" (template_argument_list"
|
||||
' ((type_descriptor) @td (#match @td "std::array<.*>"))'
|
||||
" )"
|
||||
" )"
|
||||
" (argument_list) @cast_target"
|
||||
" )"
|
||||
" )"
|
||||
") @array_bit_cast"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "array_bit_cast"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
c1 = captures[1][0]
|
||||
c4 = captures[4][0]
|
||||
arr_name: bytes = get_text(src, c1.start_byte, c1.end_byte)
|
||||
array_type: Node = captures[3][0]
|
||||
cast_target: bytes = get_text(src, c4.start_byte, c4.end_byte).strip(b"()")
|
||||
named_child = array_type.named_children[0].named_children[1].named_children[1]
|
||||
array_templ_args: bytes = get_text(
|
||||
src, named_child.start_byte, named_child.end_byte
|
||||
).strip(b"<>")
|
||||
arr_type = array_templ_args.split(b",")[0]
|
||||
arr_len = array_templ_args.split(b",")[1]
|
||||
return (
|
||||
b"union {\n"
|
||||
+ b" typeof("
|
||||
+ cast_target
|
||||
+ b") In;\n"
|
||||
+ b" "
|
||||
+ arr_type
|
||||
+ b" Out["
|
||||
+ arr_len
|
||||
+ b"];\n"
|
||||
+ b"} U_"
|
||||
+ arr_name
|
||||
+ b";\n"
|
||||
+ b"U_"
|
||||
+ arr_name
|
||||
+ b".In = "
|
||||
+ cast_target
|
||||
+ b";\n"
|
||||
+ arr_type
|
||||
+ b" *"
|
||||
+ arr_name
|
||||
+ b" = U_"
|
||||
+ arr_name
|
||||
+ b".Out;"
|
||||
)
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CheckDecoderStatus(Patch):
|
||||
"""
|
||||
Patch "Check(S, ..."
|
||||
to "Check(&S, ..."
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
' ((identifier) @fcn_name (#eq? @fcn_name "Check"))'
|
||||
" ((argument_list) @arg_list)"
|
||||
") @check_call"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "check_call"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
call_expr: Node = captures[0][0]
|
||||
first_arg: Node = captures[2][0].named_children[0]
|
||||
|
||||
call_text = get_text(src, call_expr.start_byte, call_expr.end_byte)
|
||||
first_arg_text = get_text(src, first_arg.start_byte, first_arg.end_byte)
|
||||
|
||||
return call_text.replace(first_arg_text + b",", b"&" + first_arg_text + b",")
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ClassConstructorDef(Patch):
|
||||
"""
|
||||
Removes Class constructor definitions with a field initializer list.
|
||||
Removes Class::Class(...) : ... {}
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(function_definition"
|
||||
" (function_declarator)"
|
||||
" (field_initializer_list)"
|
||||
" (compound_statement)"
|
||||
") @class_constructor"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "class_constructor"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ClassesDef(Patch):
|
||||
"""
|
||||
Patch Class definitions
|
||||
to Removes class but extracts method declarations.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "(class_specifier (_)* ((field_declaration_list) @decl_list)*) @class_specifier"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "class_specifier"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
if len(captures) < 2:
|
||||
# Forward class definition. Ignore it.
|
||||
return b""
|
||||
field_decl_list = captures[1][0]
|
||||
functions = list()
|
||||
for field_decl in field_decl_list.named_children:
|
||||
if (
|
||||
field_decl.type in "field_declaration"
|
||||
and (
|
||||
"function_declarator" in [t.type for t in field_decl.named_children]
|
||||
)
|
||||
) or field_decl.type == "template_declaration":
|
||||
# Keep comments
|
||||
sibling = field_decl.prev_named_sibling
|
||||
while sibling.type == "comment":
|
||||
functions.append(sibling)
|
||||
sibling = sibling.prev_named_sibling
|
||||
functions.append(field_decl)
|
||||
fcn_decl_text = b""
|
||||
for f in functions:
|
||||
fcn_decl_text += get_text(src, f.start_byte, f.end_byte) + b"\n"
|
||||
return fcn_decl_text
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ConstMCInstParameter(Patch):
|
||||
"""
|
||||
Patch const MCInst *MI
|
||||
to MCInst *MI
|
||||
|
||||
Removes the const qualifier from MCInst parameters because functions like MCInst_getOperand() ignore them anyway.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_declaration"
|
||||
" ((type_qualifier) @type_qualifier)"
|
||||
' ((type_identifier) @type_id (#eq? @type_id "MCInst"))'
|
||||
" (pointer_declarator) @ptr_decl"
|
||||
") @mcinst_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "mcinst_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
inst = captures[3][0]
|
||||
inst = get_text(src, inst.start_byte, inst.end_byte)
|
||||
return b"MCInst " + inst
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ConstMCOperand(Patch):
|
||||
"""
|
||||
Patch const MCOperand ...
|
||||
to MCOperand
|
||||
|
||||
Removes the const qualifier from MCOperand declarations. They are ignored by the following functions.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(declaration"
|
||||
" (type_qualifier)"
|
||||
' ((type_identifier) @tid (#eq? @tid "MCOperand"))'
|
||||
" (init_declarator) @init_decl"
|
||||
") @const_mcoperand"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "const_mcoperand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
init_decl = captures[2][0]
|
||||
init_decl = get_text(src, init_decl.start_byte, init_decl.end_byte)
|
||||
return b"MCOperand " + init_decl + b";"
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CppInitCast(Patch):
|
||||
"""
|
||||
Patch int(...)
|
||||
to (int)(...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (primitive_type) @cast_type"
|
||||
" (argument_list) @cast_target"
|
||||
") @cast"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "cast"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
cast_type: Node = captures[1][0]
|
||||
cast_target: Node = captures[2][0]
|
||||
|
||||
ctype = get_text(src, cast_type.start_byte, cast_type.end_byte)
|
||||
ctarget = get_text(src, cast_target.start_byte, cast_target.end_byte)
|
||||
return b"((" + ctype + b")" + ctarget + b")"
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CreateOperand0(Patch):
|
||||
"""
|
||||
Patch Inst.addOperand(MCOperand::createReg(...));
|
||||
to MCOperand_CreateReg0(...)
|
||||
(and equivalent for CreateImm)
|
||||
|
||||
This is the `0` variant of the CS `CreateReg`/`CreateImm` functions. It is used if the
|
||||
operand is added via `addOperand()`.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression "
|
||||
" (field_expression ((identifier) @inst_var"
|
||||
' (field_identifier) @field_id (#eq? @field_id "addOperand")))'
|
||||
" (argument_list (call_expression "
|
||||
" (qualified_identifier ((_) (identifier) @create_fcn))"
|
||||
" (argument_list) @arg_list"
|
||||
" )"
|
||||
" )"
|
||||
") @create_operand0"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "create_operand0"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get name of instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
# Get 'create[Reg/Imm]'
|
||||
op_create_fcn: Node = captures[3][0]
|
||||
# Get arg list
|
||||
op_create_args: Node = captures[4][0]
|
||||
|
||||
# Capstone spells the function with capital letter 'C' for whatever reason.
|
||||
fcn = re.sub(
|
||||
b"create",
|
||||
b"Create",
|
||||
get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte),
|
||||
)
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
|
||||
if args[0] == b"(" and args[-1] == b")":
|
||||
args = args
|
||||
return b"MCOperand_" + fcn + b"0(" + inst + b", " + args + b")"
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class CreateOperand1(Patch):
|
||||
"""
|
||||
Patch MI.insert(..., MCOperand::createReg(...));
|
||||
to MCInst_insert0(..., MCOperand_createReg1(...));
|
||||
(and equivalent for CreateImm)
|
||||
|
||||
This is the `1` variant of the CS `CreateReg`/`CreateImm` functions. It is used if the
|
||||
operand is added via `insert()`.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression "
|
||||
" (field_expression ((identifier) @MC_id"
|
||||
' ((field_identifier) @field_id (#match? @field_id "insert")))'
|
||||
" )"
|
||||
" (argument_list"
|
||||
" ((identifier) @inst_var"
|
||||
" (call_expression"
|
||||
" (qualified_identifier ((_) (identifier) @create_fcn))"
|
||||
" (argument_list) @arg_list)"
|
||||
" )"
|
||||
" )"
|
||||
") @create_operand1"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "create_operand1"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
# Get argument of .insert() call
|
||||
insert_arg: Node = captures[3][0]
|
||||
# Get 'create[Reg/Imm]'
|
||||
op_create_fcn: Node = captures[4][0]
|
||||
# CreateReg/Imm args
|
||||
op_create_args: Node = captures[5][0]
|
||||
|
||||
insert_arg_t = get_text(src, insert_arg.start_byte, insert_arg.end_byte)
|
||||
# Capstone spells the function with capital letter 'C' for whatever reason.
|
||||
fcn = re.sub(
|
||||
b"create",
|
||||
b"Create",
|
||||
get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte),
|
||||
)
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
|
||||
return (
|
||||
b"MCInst_insert0("
|
||||
+ inst
|
||||
+ b", "
|
||||
+ insert_arg_t
|
||||
+ b", "
|
||||
+ b"MCOperand_"
|
||||
+ fcn
|
||||
+ b"1("
|
||||
+ inst
|
||||
+ b", "
|
||||
+ args
|
||||
+ b"))"
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Data(Patch):
|
||||
"""
|
||||
Patch Bytes.data()
|
||||
to Bytes
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @data_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "data"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @data"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "data"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get operand variable name (Bytes, ArrayRef)
|
||||
op_var: Node = captures[1][0]
|
||||
op = get_text(src, op_var.start_byte, op_var.end_byte)
|
||||
return op
|
||||
external/capstone/suite/auto-sync/src/autosync/cpptranslator/patches/DeclarationInConditionClause.py
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DeclarationInConditionalClause(Patch):
|
||||
"""
|
||||
Patch if (DECLARATION) ...
|
||||
to DECLARATION
|
||||
if (VAR) ...
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(if_statement"
|
||||
" (condition_clause"
|
||||
" (declaration"
|
||||
" (_)"
|
||||
" ((identifier) @id)"
|
||||
" (_)"
|
||||
" ) @decl"
|
||||
" )"
|
||||
" (_) @if_body"
|
||||
") @condition_clause"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "condition_clause"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
cond = get_capture_node(captures, "condition_clause")
|
||||
for nc in cond.named_children:
|
||||
if nc.type == "if_statement":
|
||||
# Skip if statements with else if
|
||||
return get_text(src, cond.start_byte, cond.end_byte)
|
||||
declaration = get_capture_node(captures, "decl")
|
||||
identifier = get_capture_node(captures, "id")
|
||||
if_body = get_capture_node(captures, "if_body")
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
declaration = get_text(src, declaration.start_byte, declaration.end_byte)
|
||||
if_body = get_text(src, if_body.start_byte, if_body.end_byte)
|
||||
res = declaration + b";\nif (" + identifier + b")\n" + if_body
|
||||
return res
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DecodeInstruction(Patch):
|
||||
"""
|
||||
Patch decodeInstruction(..., this, STI)
|
||||
to decodeInstruction_<instr_width>(..., NULL)
|
||||
|
||||
It also removes the arguments `this, STI`.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "decodeInstruction")'
|
||||
" ((argument_list) @arg_list)"
|
||||
")) @decode_instr"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "decode_instr"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
arg_list = captures[2][0]
|
||||
args_text = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
||||
|
||||
table, mi_inst, opcode_var, address, this, sti = args_text.split(b",")
|
||||
is_32bit = (
|
||||
table[-2:].decode("utf8") == "32" or opcode_var[-2:].decode("utf8") == "32"
|
||||
)
|
||||
is_16bit = (
|
||||
table[-2:].decode("utf8") == "16" or opcode_var[-2:].decode("utf8") == "16"
|
||||
)
|
||||
args = (
|
||||
table + b", " + mi_inst + b", " + opcode_var + b", " + address + b", NULL"
|
||||
)
|
||||
|
||||
if is_16bit and not is_32bit:
|
||||
return b"decodeInstruction_2(" + args + b")"
|
||||
elif is_32bit and not is_16bit:
|
||||
return b"decodeInstruction_4(" + args + b")"
|
||||
else:
|
||||
# Cannot determine instruction width easily. Only update the calls arguments.
|
||||
return b"decodeInstruction(" + args + b")"
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DecoderCast(Patch):
|
||||
"""
|
||||
Patch Removes casts like `const MCDisassembler *Dis = static_cast<const MCDisassembler*>(Decoder);`
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(declaration"
|
||||
" (type_qualifier)*"
|
||||
' ((type_identifier) @tid (#eq? @tid "MCDisassembler"))'
|
||||
" (init_declarator"
|
||||
" (pointer_declarator)"
|
||||
" (call_expression"
|
||||
" (template_function)" # static_cast<const MCDisassembler>
|
||||
" (argument_list"
|
||||
' ((identifier) @id (#eq? @id "Decoder"))'
|
||||
" )"
|
||||
" )"
|
||||
" )"
|
||||
") @decoder_cast"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "decoder_cast"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class DecoderParameter(Patch):
|
||||
"""
|
||||
Patch const MCDisassembler *Decoder
|
||||
to const void *Decoder
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_declaration"
|
||||
" ((type_qualifier) @type_qualifier)"
|
||||
' ((type_identifier) @type_id (#eq? @type_id "MCDisassembler"))'
|
||||
" (pointer_declarator) @ptr_decl"
|
||||
") @decoder_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "decoder_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b"const void *Decoder"
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FallThrough(Patch):
|
||||
"""
|
||||
Patch [[fallthrough]]
|
||||
to // fall through
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return '(attributed_statement) @attr (#match? @attr "fallthrough")'
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "attr"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b"// fall through"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FeatureBits(Patch):
|
||||
"""
|
||||
Patch featureBits[FLAG]
|
||||
to ARCH_getFeatureBits(Inst->csh->mode, FLAG)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, arch: bytes):
|
||||
self.arch = arch
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for featureBits usage.
|
||||
return (
|
||||
"(subscript_expression "
|
||||
' ((identifier) @id (#match? @id "[fF]eatureBits"))'
|
||||
" (subscript_argument_list ((qualified_identifier) @qid))"
|
||||
") @feature_bits"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "feature_bits"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get flag name of feature bit.
|
||||
qualified_id: Node = captures[2][0]
|
||||
flag = get_text(src, qualified_id.start_byte, qualified_id.end_byte)
|
||||
mcinst_var_name = get_MCInst_var_name(src, qualified_id)
|
||||
return (
|
||||
self.arch
|
||||
+ b"_getFeatureBits("
|
||||
+ mcinst_var_name
|
||||
+ b"->csh->mode, "
|
||||
+ flag
|
||||
+ b")"
|
||||
)
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FeatureBitsDecl(Patch):
|
||||
"""
|
||||
Patch ... featureBits = ...
|
||||
to REMOVED
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for featureBits declarations.
|
||||
return (
|
||||
"(declaration (init_declarator (reference_declarator "
|
||||
'((identifier) @id (#match? @id "[fF]eatureBits"))))) @feature_bits_decl'
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "feature_bits_decl"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Remove declaration
|
||||
return b""
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class FieldFromInstr(Patch):
|
||||
"""
|
||||
Patch fieldFromInstruction(...)
|
||||
to fieldFromInstruction_<instr_width>(...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for fieldFromInstruction() calls.
|
||||
return (
|
||||
"(call_expression"
|
||||
' ((identifier) @fcn_name (#eq? @fcn_name "fieldFromInstruction"))'
|
||||
" (argument_list ((identifier) @first_arg) (_) (_))"
|
||||
") @field_from_instr"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "field_from_instr"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
ffi_call: Node = captures[0][0]
|
||||
ffi_first_arg: Node = captures[2][0]
|
||||
param_list_caller = get_function_params_of_node(ffi_call)
|
||||
ffi_first_arg_text = get_text(
|
||||
src, ffi_first_arg.start_byte, ffi_first_arg.end_byte
|
||||
).decode("utf8")
|
||||
|
||||
# Determine width of instruction by the variable name.
|
||||
if ffi_first_arg_text[-2:] == "32":
|
||||
inst_width = b"4"
|
||||
elif ffi_first_arg_text[-2:] == "16":
|
||||
inst_width = b"2"
|
||||
else:
|
||||
# Get the Val/Inst parameter.
|
||||
# Its type determines the instruction width.
|
||||
if len(param_list_caller.named_children) == 1:
|
||||
# If function just return fieldFromInstruction(...)
|
||||
inst_param: Node = param_list_caller.named_children[0]
|
||||
else:
|
||||
inst_param = param_list_caller.named_children[1]
|
||||
inst_param_text = get_text(src, inst_param.start_byte, inst_param.end_byte)
|
||||
|
||||
# Search for the 'Inst' parameter and determine its type
|
||||
# and with it the width of the instruction.
|
||||
inst_type = inst_param_text.split(b" ")[0]
|
||||
if inst_type:
|
||||
if inst_type in [b"uint64_t"]:
|
||||
inst_width = b"8"
|
||||
elif inst_type in [b"unsigned", b"uint32_t"]:
|
||||
inst_width = b"4"
|
||||
elif inst_type in [b"uint16_t"]:
|
||||
inst_width = b"2"
|
||||
elif inst_type in [b"InsnType"]:
|
||||
# Case means the decode function inherits the type from
|
||||
# a template argument InsnType. The InsnType template argument
|
||||
# is the type of integer holding the instruction bytes.
|
||||
# This type is defined in ARCHDisassembler on calling the right macro.
|
||||
# Hence, we do not know at this point of patching which type it might be.
|
||||
# It needs to call fieldOfInstruction_X() which detects dynamically which
|
||||
# integer type might hold the bytes (e.g. a uint32_t or uint16_t).
|
||||
# You can check it manually in ARCHDisassembler.c, but the script can't.
|
||||
#
|
||||
# Here we just create a function with the postfix fieldFromInstruction_w (for width).
|
||||
# This function must be implemented by hand, and check MCInst for the actual bit width.
|
||||
# The bit width must be set in the ARCHDisassembler.c. Just add the code there by hand.
|
||||
# Then call fieldFromInstruction_4, fieldFromInstruction_2 appropriately.
|
||||
log.warning(
|
||||
"Variable fieldFromInstruction width detected.\n"
|
||||
"Please implement fieldFromInstruction_w() and call "
|
||||
"fieldFromInstruction_4, fieldFromInstruction_2 appropriately.\n"
|
||||
"In fieldFromInstruction_w() check MCInst for the actual bit width.\n"
|
||||
"The bit width must be set in the ARCHDisassembler.c. Just add the code there by hand."
|
||||
)
|
||||
inst_width = b"w"
|
||||
else:
|
||||
raise ValueError(f"Type {inst_type} not handled.")
|
||||
else:
|
||||
# Needs manual fix
|
||||
return get_text(src, ffi_call.start_byte, ffi_call.end_byte)
|
||||
return re.sub(
|
||||
rb"fieldFromInstruction",
|
||||
b"fieldFromInstruction_%s" % inst_width,
|
||||
get_text(src, ffi_call.start_byte, ffi_call.end_byte),
|
||||
)
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetNumOperands(Patch):
|
||||
"""
|
||||
Patch MI.getNumOperands()
|
||||
to MCInst_getNumOperands(MI)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "getNumOperands"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @get_num_operands"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_num_operands"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable name: MI, Inst etc.
|
||||
inst_var: Node = captures[1][0]
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
return b"MCInst_getNumOperands(" + inst + b")"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetOpcode(Patch):
|
||||
"""
|
||||
Patch Inst.getOpcode()
|
||||
to MCInst_getOpcode(Inst)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression ("
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getOpcode")))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @get_opcode"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_opcode"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
arg_list: Node = captures[3][0]
|
||||
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte)
|
||||
if args != b"()":
|
||||
args = b", " + args
|
||||
else:
|
||||
args = b""
|
||||
return b"MCInst_getOpcode(" + inst + args + b")"
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetOperand(Patch):
|
||||
"""
|
||||
Patch MI.getOperand(...)
|
||||
to MCInst_getOperand(MI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "getOperand"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @get_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get instruction variable name (MI, Inst)
|
||||
inst_var: Node = captures[1][0]
|
||||
# Arguments of getOperand(...)
|
||||
get_op_args = captures[3][0]
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, get_op_args.start_byte, get_op_args.end_byte)
|
||||
return b"MCInst_getOperand(" + inst + b", " + args + b")"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetOperandRegImm(Patch):
|
||||
"""
|
||||
Patch OPERAND.getReg()
|
||||
to MCOperand_getReg(OPERAND)
|
||||
|
||||
Same for getImm()|getExpr
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" ((_) @operand)"
|
||||
' ((field_identifier) @field_id (#match? @field_id "get(Reg|Imm|Expr)"))'
|
||||
" )"
|
||||
' ((argument_list) @arg_list (#eq? @arg_list "()"))'
|
||||
") @get_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# The operand
|
||||
operand: Node = get_capture_node(captures, "operand")
|
||||
# 'getReg()/getImm()\getExpr'
|
||||
get_reg_imm = get_capture_node(captures, "field_id")
|
||||
|
||||
fcn = get_text(src, get_reg_imm.start_byte, get_reg_imm.end_byte)
|
||||
op = get_text(src, operand.start_byte, operand.end_byte)
|
||||
return b"MCOperand_" + fcn + b"(" + op + b")"
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import (
|
||||
get_capture_node,
|
||||
get_MCInst_var_name,
|
||||
get_text,
|
||||
)
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetRegClass(Patch):
|
||||
"""
|
||||
Patch MRI.getRegClass(...)
|
||||
to MCRegisterInfo_getRegClass(Inst->MRI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" (_)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getRegClass"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @get_reg_class"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_reg_class"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
arg_list: Node = get_capture_node(captures, "arg_list")
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
||||
mcinst_var = get_MCInst_var_name(
|
||||
src, get_capture_node(captures, "get_reg_class")
|
||||
)
|
||||
res = b"MCRegisterInfo_getRegClass(" + mcinst_var + b"->MRI, " + args + b")"
|
||||
return res
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetRegFromClass(Patch):
|
||||
"""
|
||||
Patch <ARCH>MCRegisterClasses[<ARCH>::FPR128RegClassID].getRegister(RegNo);
|
||||
to <ARCH>MCRegisterClasses[<ARCH>::FPR128RegClassID].RegsBegin[RegNo];
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
' ((_) @operand (#match? @operand ".+MCRegisterClasses.*"))'
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getRegister"))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @get_reg_from_class"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_reg_from_class"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Table
|
||||
table: Node = get_capture_node(captures, "operand")
|
||||
# args
|
||||
getter_args = get_capture_node(captures, "arg_list")
|
||||
|
||||
tbl = get_text(src, table.start_byte, table.end_byte)
|
||||
args = get_text(src, getter_args.start_byte, getter_args.end_byte)
|
||||
|
||||
res = tbl + b".RegsBegin" + args.replace(b"(", b"[").replace(b")", b"]")
|
||||
return res
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class GetSubReg(Patch):
|
||||
"""
|
||||
Patch MRI.getSubReg(...);
|
||||
to MCRegisterInfo_getSubReg(MI->MRI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression ("
|
||||
" (identifier)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "getSubReg")))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @get_sub_reg"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "get_sub_reg"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get arg list
|
||||
op_create_args: Node = captures[2][0]
|
||||
|
||||
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte).strip(
|
||||
b"()"
|
||||
)
|
||||
mcinst_var_name = get_MCInst_var_name(src, op_create_args)
|
||||
return b"MCRegisterInfo_getSubReg(" + mcinst_var_name + b"->MRI, " + args + b")"
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.Helper import fail_exit
|
||||
|
||||
|
||||
def get_function_params_of_node(n: Node) -> Node:
|
||||
"""
|
||||
Returns for a given node the parameters of the function this node is a children from.
|
||||
Or None if the node is not part of a function definition.
|
||||
"""
|
||||
fcn_def: Node = n
|
||||
while fcn_def.type != "function_definition":
|
||||
if fcn_def.parent == None:
|
||||
# root node reached
|
||||
return None
|
||||
fcn_def = fcn_def.parent
|
||||
|
||||
# Get parameter list of the function definition
|
||||
param_list: Node = None
|
||||
for child in fcn_def.children:
|
||||
if child.type == "function_declarator":
|
||||
param_list = child.children[1]
|
||||
break
|
||||
if not param_list:
|
||||
log.warning(f"Could not find the functions parameter list for {n.text}")
|
||||
return param_list
|
||||
|
||||
|
||||
def get_MCInst_var_name(src: bytes, n: Node) -> bytes:
|
||||
"""Searches for the name of the parameter of type MCInst and returns it."""
|
||||
params = get_function_params_of_node(n)
|
||||
mcinst_var_name = b""
|
||||
|
||||
if params:
|
||||
for p in params.named_children:
|
||||
p_text = get_text(src, p.start_byte, p.end_byte)
|
||||
if b"MCInst" not in p_text:
|
||||
continue
|
||||
mcinst_var_name = p_text.split((b"&" if b"&" in p_text else b"*"))[1]
|
||||
break
|
||||
if mcinst_var_name == b"":
|
||||
log.debug("Could not find `MCInst` variable name. Defaulting to `Inst`.")
|
||||
mcinst_var_name = b"Inst"
|
||||
return mcinst_var_name
|
||||
|
||||
|
||||
def template_param_list_to_dict(param_list: Node) -> [dict]:
|
||||
if param_list.type != "template_parameter_list":
|
||||
log.fatal(
|
||||
f"Wrong node type '{param_list.type}'. Not 'template_parameter_list'."
|
||||
)
|
||||
exit(1)
|
||||
pl = list()
|
||||
for c in param_list.named_children:
|
||||
if c.type == "type_parameter_declaration":
|
||||
type_decl = {
|
||||
"prim_type": False,
|
||||
"type": "",
|
||||
"identifier": c.children[1].text,
|
||||
}
|
||||
pl.append(type_decl)
|
||||
else:
|
||||
pl.append(parameter_declaration_to_dict(c))
|
||||
return pl
|
||||
|
||||
|
||||
def parameter_declaration_to_dict(param_decl: Node) -> dict:
|
||||
if param_decl.type != "parameter_declaration":
|
||||
log.fatal(
|
||||
f"Wrong node type '{param_decl.type}'. Should be 'parameter_declaration'."
|
||||
)
|
||||
exit(1)
|
||||
return {
|
||||
"prim_type": param_decl.children[0].type == "primitive_type",
|
||||
"type": param_decl.children[0].text,
|
||||
"identifier": param_decl.children[1].text,
|
||||
}
|
||||
|
||||
|
||||
def get_text(src: bytes, start_byte: int, end_byte: int) -> bytes:
|
||||
"""Workaround for https://github.com/tree-sitter/py-tree-sitter/issues/122"""
|
||||
return src[start_byte:end_byte]
|
||||
|
||||
|
||||
def get_text_from_node(src: bytes, node: Node) -> bytes:
|
||||
return src[node.start_byte : node.end_byte]
|
||||
|
||||
|
||||
def namespace_enum(src: bytes, ns_id: bytes, enum: Node) -> bytes:
|
||||
"""
|
||||
Alters an enum in the way that it prepends the namespace id to every enum member.
|
||||
And defines it as a type.
|
||||
Example: naemspace_id = "ARM"
|
||||
enum { X } -> typedef enum { ARM_X } ARM_enum
|
||||
"""
|
||||
enumerator_list: Node = None
|
||||
type_id: Node = None
|
||||
primary_tid_set = False
|
||||
for c in enum.named_children:
|
||||
if c.type == "enumerator_list":
|
||||
enumerator_list = c
|
||||
elif c.type == "type_identifier" and not primary_tid_set:
|
||||
type_id = c
|
||||
primary_tid_set = True
|
||||
|
||||
if not enumerator_list and not type_id:
|
||||
log.fatal("Could not find enumerator_list or enum type_identifier.")
|
||||
exit(1)
|
||||
|
||||
tid = get_text(src, type_id.start_byte, type_id.end_byte) if type_id else None
|
||||
elist = get_text(src, enumerator_list.start_byte, enumerator_list.end_byte)
|
||||
for e in enumerator_list.named_children:
|
||||
if e.type == "enumerator":
|
||||
enum_entry_text = get_text(src, e.start_byte, e.end_byte)
|
||||
elist = elist.replace(enum_entry_text, ns_id + b"_" + enum_entry_text)
|
||||
|
||||
if tid:
|
||||
new_enum = b"typedef enum " + tid + b" " + elist + b"\n " + ns_id + b"_" + tid
|
||||
else:
|
||||
new_enum = b"enum " + b" " + elist + b"\n"
|
||||
return new_enum
|
||||
|
||||
|
||||
def namespace_fcn_def(src: bytes, ns_id: bytes, fcn_def: Node) -> bytes:
|
||||
fcn_id: Node = None
|
||||
for c in fcn_def.named_children:
|
||||
if c.type == "function_declarator":
|
||||
fcn_id = c.named_children[0]
|
||||
break
|
||||
elif c.named_children and c.named_children[0].type == "function_declarator":
|
||||
fcn_id = c.named_children[0].named_children[0]
|
||||
break
|
||||
if not fcn_id:
|
||||
# Not a function declaration
|
||||
return get_text(src, fcn_def.start_byte, fcn_def.end_byte)
|
||||
fcn_id_text = get_text(src, fcn_id.start_byte, fcn_id.end_byte)
|
||||
fcn_def_text = get_text(src, fcn_def.start_byte, fcn_def.end_byte)
|
||||
res = re.sub(fcn_id_text, ns_id + b"_" + fcn_id_text, fcn_def_text)
|
||||
return res
|
||||
|
||||
|
||||
def namespace_struct(src: bytes, ns_id: bytes, struct: Node) -> bytes:
|
||||
"""
|
||||
Defines a struct as a type.
|
||||
Example: naemspace_id = "ARM"
|
||||
struct id { X } -> typedef struct { } ARM_id
|
||||
"""
|
||||
type_id: Node = None
|
||||
field_list: Node = None
|
||||
for c in struct.named_children:
|
||||
if c.type == "type_identifier":
|
||||
type_id = c
|
||||
elif c.type == "base_class_clause":
|
||||
# Inheritances should be fixed manually.
|
||||
return get_text(src, struct.start_byte, struct.end_byte)
|
||||
elif c.type == "field_declaration_list":
|
||||
field_list = c
|
||||
|
||||
if not (type_id and field_list):
|
||||
log.fatal("Could not find struct type_identifier or field declaration list.")
|
||||
exit(1)
|
||||
|
||||
tid = get_text(src, type_id.start_byte, type_id.end_byte)
|
||||
fields = get_text(src, field_list.start_byte, field_list.end_byte)
|
||||
|
||||
typed_struct = (
|
||||
b"typedef struct " + tid + b" " + fields + b"\n " + ns_id + b"_" + tid
|
||||
)
|
||||
return typed_struct
|
||||
|
||||
|
||||
def parse_function_capture(
|
||||
capture: list[tuple[Node, str]], src: bytes
|
||||
) -> tuple[list[bytes], bytes, bytes, bytes, bytes, bytes]:
|
||||
"""
|
||||
Parses the capture of a (template) function definition or declaration and returns the byte strings
|
||||
for each node in the following order:
|
||||
|
||||
list[template_args], storage_class_identifiers, return_type_id, function_name, function_params, compound_stmt
|
||||
|
||||
If any of those is not present it returns an empty byte string for this position.
|
||||
"""
|
||||
temp_args = b""
|
||||
st_class_ids = b""
|
||||
ret_type = b""
|
||||
func_name = b""
|
||||
func_params = b""
|
||||
comp_stmt = b""
|
||||
for node, node_name in capture:
|
||||
t = get_text(src, node.start_byte, node.end_byte)
|
||||
match node.type:
|
||||
case "template_declaration":
|
||||
continue
|
||||
case "template_parameter_list":
|
||||
temp_args += t if not temp_args else b" " + t
|
||||
case "storage_class_specifier":
|
||||
st_class_ids += b" " + t
|
||||
case "type_identifier" | "primitive_type":
|
||||
ret_type += b" " + t
|
||||
case "identifier":
|
||||
func_name += t if not func_name else b" " + t
|
||||
case "parameter_list":
|
||||
func_params += t if not func_params else b" " + t
|
||||
case "compound_statement":
|
||||
comp_stmt += t if not comp_stmt else b" " + t
|
||||
case _:
|
||||
raise NotImplementedError(f"Node type {node.type} not handled.")
|
||||
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
return (
|
||||
TemplateCollector.templ_params_to_list(temp_args),
|
||||
st_class_ids,
|
||||
ret_type,
|
||||
func_name,
|
||||
func_params,
|
||||
comp_stmt,
|
||||
)
|
||||
|
||||
|
||||
def get_capture_node(captures: [(Node, str)], name: str) -> Node:
|
||||
"""
|
||||
Returns the captured node with the given name.
|
||||
"""
|
||||
for c in captures:
|
||||
if c[1] == name:
|
||||
return c[0]
|
||||
fail_exit(f'Capture "{name}" is not in captures:\n{captures}')
|
||||
+487
@@ -0,0 +1,487 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Includes(Patch):
|
||||
"""
|
||||
Patch LLVM includes
|
||||
to Capstone includes
|
||||
"""
|
||||
|
||||
include_count = dict()
|
||||
|
||||
def __init__(self, priority: int, arch: str):
|
||||
self.arch = arch
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "(preproc_include) @preproc_include"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "preproc_include"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
filename = kwargs["filename"]
|
||||
if filename not in self.include_count:
|
||||
self.include_count[filename] = 1
|
||||
else:
|
||||
self.include_count[filename] += 1
|
||||
|
||||
include_text = get_text(src, captures[0][0].start_byte, captures[0][0].end_byte)
|
||||
# Special cases, which appear somewhere in the code.
|
||||
if b"GenDisassemblerTables.inc" in include_text:
|
||||
return (
|
||||
b'#include "'
|
||||
+ bytes(self.arch, "utf8")
|
||||
+ b'GenDisassemblerTables.inc"\n\n'
|
||||
)
|
||||
elif b"GenAsmWriter.inc" in include_text:
|
||||
return b'#include "' + bytes(self.arch, "utf8") + b'GenAsmWriter.inc"\n\n'
|
||||
elif b"GenSystemOperands.inc" in include_text:
|
||||
return (
|
||||
b'#include "' + bytes(self.arch, "utf8") + b'GenSystemOperands.inc"\n\n'
|
||||
)
|
||||
|
||||
if self.include_count[filename] > 1:
|
||||
# Only the first include is replaced with all CS includes.
|
||||
return b""
|
||||
|
||||
# All includes which belong to the source files top.
|
||||
res = get_general_inc()
|
||||
match self.arch:
|
||||
case "ARM":
|
||||
return res + get_ARM_includes(filename) + get_general_macros()
|
||||
case "PPC":
|
||||
return res + get_PPC_includes(filename) + get_general_macros()
|
||||
case "AArch64":
|
||||
return res + get_AArch64_includes(filename) + get_general_macros()
|
||||
case "LoongArch":
|
||||
return res + get_LoongArch_includes(filename) + get_general_macros()
|
||||
case "Mips":
|
||||
return res + get_Mips_includes(filename) + get_general_macros()
|
||||
case "SystemZ":
|
||||
return res + get_SystemZ_includes(filename) + get_general_macros()
|
||||
case "Xtensa":
|
||||
return res + get_Xtensa_includes(filename) + get_general_macros()
|
||||
case "ARC":
|
||||
return res + get_ARC_includes(filename) + get_general_macros()
|
||||
case "Sparc":
|
||||
return res + get_sparc_includes(filename) + get_general_macros()
|
||||
case "TEST_ARCH":
|
||||
return res + b"test_output"
|
||||
case _:
|
||||
log.fatal(f"Includes of {self.arch} not handled.")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_general_inc() -> bytes:
|
||||
return (
|
||||
b"#include <stdio.h>\n"
|
||||
+ b"#include <string.h>\n"
|
||||
+ b"#include <stdlib.h>\n"
|
||||
+ b"#include <capstone/platform.h>\n\n"
|
||||
)
|
||||
|
||||
|
||||
def get_PPC_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "PPCDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "PPCLinkage.h"\n'
|
||||
+ b'#include "PPCMapping.h"\n'
|
||||
+ b'#include "PPCMCTargetDesc.h"\n'
|
||||
+ b'#include "PPCPredicates.h"\n\n'
|
||||
)
|
||||
case "PPCInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "PPCInstrInfo.h"\n'
|
||||
+ b'#include "PPCInstPrinter.h"\n'
|
||||
+ b'#include "PPCLinkage.h"\n'
|
||||
+ b'#include "PPCMCTargetDesc.h"\n'
|
||||
+ b'#include "PPCMapping.h"\n'
|
||||
+ b'#include "PPCPredicates.h"\n\n'
|
||||
+ b'#include "PPCRegisterInfo.h"\n\n'
|
||||
)
|
||||
case "PPCInstPrinter.h":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "PPCMCTargetDesc.h"\n\n'
|
||||
)
|
||||
case "PPCMCTargetDesc.h":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for PPC source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_ARM_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "ARMDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "ARMAddressingModes.h"\n'
|
||||
+ b'#include "ARMBaseInfo.h"\n'
|
||||
+ b'#include "ARMDisassemblerExtension.h"\n'
|
||||
+ b'#include "ARMInstPrinter.h"\n'
|
||||
+ b'#include "ARMLinkage.h"\n'
|
||||
+ b'#include "ARMMapping.h"\n\n'
|
||||
+ b"#define GET_INSTRINFO_MC_DESC\n"
|
||||
+ b'#include "ARMGenInstrInfo.inc"\n\n'
|
||||
)
|
||||
case "ARMInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../Mapping.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "ARMAddressingModes.h"\n'
|
||||
+ b'#include "ARMBaseInfo.h"\n'
|
||||
+ b'#include "ARMDisassemblerExtension.h"\n'
|
||||
+ b'#include "ARMInstPrinter.h"\n'
|
||||
+ b'#include "ARMLinkage.h"\n'
|
||||
+ b'#include "ARMMapping.h"\n\n'
|
||||
+ b"#define GET_BANKEDREG_IMPL\n"
|
||||
+ b'#include "ARMGenSystemRegister.inc"\n'
|
||||
)
|
||||
case "ARMInstPrinter.h":
|
||||
return (
|
||||
b'#include "ARMMapping.h"\n\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../utils.h"\n\n'
|
||||
)
|
||||
case "ARMBaseInfo.cpp":
|
||||
return b'#include "ARMBaseInfo.h"\n\n'
|
||||
case "ARMAddressingModes.h":
|
||||
return b"#include <assert.h>\n" + b'#include "../../MathExtras.h"\n\n'
|
||||
log.fatal(f"No includes given for ARM source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_AArch64_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "AArch64Disassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "AArch64AddressingModes.h"\n'
|
||||
+ b'#include "AArch64BaseInfo.h"\n'
|
||||
+ b'#include "AArch64DisassemblerExtension.h"\n'
|
||||
+ b'#include "AArch64Linkage.h"\n'
|
||||
+ b'#include "AArch64Mapping.h"\n\n'
|
||||
+ b"#define GET_INSTRINFO_MC_DESC\n"
|
||||
+ b'#include "AArch64GenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "AArch64GenInstrInfo.inc"\n\n'
|
||||
)
|
||||
case "AArch64InstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "AArch64AddressingModes.h"\n'
|
||||
+ b'#include "AArch64BaseInfo.h"\n'
|
||||
+ b'#include "AArch64DisassemblerExtension.h"\n'
|
||||
+ b'#include "AArch64InstPrinter.h"\n'
|
||||
+ b'#include "AArch64Linkage.h"\n'
|
||||
+ b'#include "AArch64Mapping.h"\n\n'
|
||||
+ b"#define GET_BANKEDREG_IMPL\n"
|
||||
+ b'#include "AArch64GenSystemOperands.inc"\n\n'
|
||||
+ b"#define CONCATs(a, b) CONCATS(a, b)\n"
|
||||
+ b"#define CONCATS(a, b) a##b\n\n"
|
||||
)
|
||||
case "AArch64InstPrinter.h":
|
||||
return (
|
||||
b'#include "AArch64Mapping.h"\n\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../utils.h"\n\n'
|
||||
)
|
||||
case "AArch64BaseInfo.cpp":
|
||||
return b'#include "AArch64BaseInfo.h"\n\n'
|
||||
case "AArch64BaseInfo.h":
|
||||
return (
|
||||
b'#include "../../utils.h"\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "AArch64GenRegisterInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "AArch64GenInstrInfo.inc"\n\n'
|
||||
)
|
||||
case "AArch64AddressingModes.h":
|
||||
return b"#include <assert.h>\n" + b'#include "../../MathExtras.h"\n\n'
|
||||
log.fatal(f"No includes given for AArch64 source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_LoongArch_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "LoongArchDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b'#include "LoongArchDisassemblerExtension.h"\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "LoongArchInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "LoongArchMapping.h"\n'
|
||||
+ b'#include "LoongArchInstPrinter.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "LoongArchGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "LoongArchInstPrinter.h":
|
||||
return (
|
||||
b'#include "../../MCInstPrinter.h"\n' + b'#include "../../cs_priv.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for LoongArch source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_Mips_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "MipsDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "MipsGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "MipsGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "MipsGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "MipsInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "MipsMapping.h"\n'
|
||||
+ b'#include "MipsInstPrinter.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "MipsGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "MipsGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "MipsGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "MipsInstPrinter.h":
|
||||
return (
|
||||
b'#include "../../MCInstPrinter.h"\n' + b'#include "../../cs_priv.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for Mips source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_SystemZ_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "SystemZDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../cs_priv.h"\n'
|
||||
+ b'#include "../../utils.h"\n\n'
|
||||
+ b'#include "SystemZMCTargetDesc.h"\n'
|
||||
+ b'#include "SystemZDisassemblerExtension.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "SystemZInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../MCAsmInfo.h"\n'
|
||||
+ b'#include "SystemZMapping.h"\n'
|
||||
+ b'#include "SystemZInstPrinter.h"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_INSTRINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_ENUM\n"
|
||||
+ b'#include "SystemZGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
case "SystemZInstPrinter.h":
|
||||
return b"\n"
|
||||
case "SystemZMCTargetDesc.h":
|
||||
return (
|
||||
b'#include "../../MCInstPrinter.h"\n' + b'#include "../../cs_priv.h"\n'
|
||||
)
|
||||
case "SystemZMCTargetDesc.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n\n'
|
||||
+ b'#include "SystemZMCTargetDesc.h"\n'
|
||||
+ b'#include "SystemZInstPrinter.h"\n\n'
|
||||
+ b"#define GET_INSTRINFO_MC_DESC\n"
|
||||
+ b"#define ENABLE_INSTR_PREDICATE_VERIFIER\n"
|
||||
+ b'#include "SystemZGenInstrInfo.inc"\n\n'
|
||||
+ b"#define GET_SUBTARGETINFO_MC_DESC\n"
|
||||
+ b'#include "SystemZGenSubtargetInfo.inc"\n\n'
|
||||
+ b"#define GET_REGINFO_MC_DESC\n"
|
||||
+ b'#include "SystemZGenRegisterInfo.inc"\n\n'
|
||||
)
|
||||
log.fatal(f"No includes given for SystemZ source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_Xtensa_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "XtensaDisassembler.cpp":
|
||||
return b"""
|
||||
#include "../../MathExtras.h"
|
||||
#include "../../MCDisassembler.h"
|
||||
#include "../../MCFixedLenDisassembler.h"
|
||||
#include "../../SStream.h"
|
||||
#include "../../cs_priv.h"
|
||||
#include "priv.h"
|
||||
|
||||
#define GET_INSTRINFO_MC_DESC
|
||||
#include "XtensaGenInstrInfo.inc"
|
||||
|
||||
"""
|
||||
case "XtensaInstPrinter.cpp":
|
||||
return b"""
|
||||
#include "../../MCInstPrinter.h"
|
||||
#include "../../SStream.h"
|
||||
#include "XtensaMapping.h"
|
||||
#include "priv.h"
|
||||
"""
|
||||
case _:
|
||||
return b""
|
||||
|
||||
|
||||
def get_ARC_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "ARCDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../utils.h"\n'
|
||||
)
|
||||
case "ARCInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "../../SStream.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstPrinter.h"\n'
|
||||
+ b'#include "ARCInfo.h"\n'
|
||||
+ b'#include "ARCInstPrinter.h"\n'
|
||||
+ b'#include "ARCLinkage.h"\n'
|
||||
+ b'#include "ARCMapping.h"\n'
|
||||
)
|
||||
case "ARCInstPrinter.h":
|
||||
return b'#include "../../SStream.h"\n' + b'#include "../../MCInst.h"\n'
|
||||
log.fatal(f"No includes given for ARC source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_sparc_includes(filename: str) -> bytes:
|
||||
match filename:
|
||||
case "SparcDisassembler.cpp":
|
||||
return (
|
||||
b'#include "../../MCDisassembler.h"\n'
|
||||
+ b'#include "../../MCFixedLenDisassembler.h"\n'
|
||||
+ b'#include "SparcDisassemblerExtension.h"\n'
|
||||
+ b'#include "SparcLinkage.h"\n'
|
||||
+ b'#include "SparcMapping.h"\n'
|
||||
+ b'#include "SparcMCTargetDesc.h"\n'
|
||||
)
|
||||
case "SparcInstPrinter.cpp":
|
||||
return (
|
||||
b'#include "SparcInstrInfo.h"\n'
|
||||
+ b'#include "SparcInstPrinter.h"\n'
|
||||
+ b'#include "SparcLinkage.h"\n'
|
||||
+ b'#include "SparcMCTargetDesc.h"\n'
|
||||
+ b'#include "SparcMapping.h"\n'
|
||||
+ b'#include "SparcRegisterInfo.h"\n\n'
|
||||
)
|
||||
case "SparcInstPrinter.h":
|
||||
return b'#include "SparcMCTargetDesc.h"\n\n'
|
||||
case "SparcMCTargetDesc.h":
|
||||
return (
|
||||
b'#include "../../LEB128.h"\n'
|
||||
+ b'#include "../../MathExtras.h"\n'
|
||||
+ b'#include "../../MCInst.h"\n'
|
||||
+ b'#include "../../MCInstrDesc.h"\n'
|
||||
+ b'#include "../../MCRegisterInfo.h"\n'
|
||||
)
|
||||
log.fatal(f"No includes given for Sparc source file: {filename}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def get_general_macros():
|
||||
return (
|
||||
b"#define CONCAT(a, b) CONCAT_(a, b)\n" b"#define CONCAT_(a, b) a ## _ ## b\n"
|
||||
)
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class InlineToStaticInline(Patch):
|
||||
"""
|
||||
Removes the qualified identifier of the class from method definitions.
|
||||
Translating them to functions.
|
||||
|
||||
Patch inline void FUNCTION(...) {...}
|
||||
to static inline void FUNCTION(...) {...}
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_definition"
|
||||
' ((storage_class_specifier) @scs (#eq? @scs "inline"))'
|
||||
" (_)+"
|
||||
") @inline_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "inline_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
inline_def = captures[0][0]
|
||||
inline_def = get_text(src, inline_def.start_byte, inline_def.end_byte)
|
||||
return b"static " + inline_def
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class IsOptionalDef(Patch):
|
||||
"""
|
||||
Patch OpInfo[i].isOptionalDef()
|
||||
to MCOperandInfo_isOptionalDef(&OpInfo[i])
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" (subscript_expression"
|
||||
" ((identifier) @op_info_var)"
|
||||
" ((_) @index)"
|
||||
" )"
|
||||
' ((field_identifier) @fid (#eq? @fid "isOptionalDef"))'
|
||||
" )"
|
||||
") @is_optional_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_optional_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
op_info_var = captures[1][0]
|
||||
index = captures[2][0]
|
||||
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
|
||||
index = get_text(src, index.start_byte, index.end_byte)
|
||||
return b"MCOperandInfo_isOptionalDef(&" + op_info_var + index + b")"
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class IsPredicate(Patch):
|
||||
"""
|
||||
Patch OpInfo[i].isPredicate()
|
||||
to MCOperandInfo_isPredicate(&OpInfo[i])
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" (subscript_expression"
|
||||
" ((identifier) @op_info_var)"
|
||||
" ((_) @index)"
|
||||
" )"
|
||||
' ((field_identifier) @fid (#eq? @fid "isPredicate"))'
|
||||
" )"
|
||||
") @is_predicate"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_predicate"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
op_info_var = captures[1][0]
|
||||
index = captures[2][0]
|
||||
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
|
||||
index = get_text(src, index.start_byte, index.end_byte)
|
||||
return b"MCOperandInfo_isPredicate(&" + op_info_var + index + b")"
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class IsOperandRegImm(Patch):
|
||||
"""
|
||||
Patch OPERAND.isReg()
|
||||
to MCOperand_isReg(OPERAND)
|
||||
|
||||
Same for isImm() | isExpr()
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
" ((_) @operand)"
|
||||
' ((field_identifier) @field_id (#match? @field_id "is(Reg|Imm|Expr)"))'
|
||||
" )"
|
||||
" (argument_list)"
|
||||
") @is_operand"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_operand"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# The operand
|
||||
operand: Node = captures[1][0]
|
||||
# 'isReg()/isImm()/isExpr'
|
||||
get_reg_imm = captures[2][0]
|
||||
|
||||
fcn = get_text(src, get_reg_imm.start_byte, get_reg_imm.end_byte)
|
||||
op = get_text(src, operand.start_byte, operand.end_byte)
|
||||
return b"MCOperand_" + fcn + b"(" + op + b")"
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class LLVMFallThrough(Patch):
|
||||
"""
|
||||
Patch Remove LLVM_FALLTHROUGH
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(expression_statement"
|
||||
' ((identifier) @id (#eq? @id "LLVM_FALLTHROUGH"))'
|
||||
") @llvm_fall_through"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "llvm_fall_through"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# Copyright © 2024 Billow <billow.fun@gmail.com>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class LLVM_DEBUG(Patch):
|
||||
"""
|
||||
Patch LLVM_DEBUG(dbgs() << "Error msg")
|
||||
to ""
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return """
|
||||
(call_expression (
|
||||
(identifier) @fcn_name (#eq? @fcn_name "LLVM_DEBUG")
|
||||
(argument_list (
|
||||
(binary_expression (
|
||||
(call_expression)
|
||||
(string_literal) @err_msg
|
||||
))
|
||||
))
|
||||
)) @llvm_debug"""
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "llvm_debug"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class LLVMUnreachable(Patch):
|
||||
"""
|
||||
Patch llvm_unreachable("Error msg")
|
||||
to assert(0 && "Error msg")
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "llvm_unreachable")'
|
||||
" (argument_list) @err_msg"
|
||||
")) @llvm_unreachable"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "llvm_unreachable"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
err_msg = captures[2][0]
|
||||
err_msg = get_text(src, err_msg.start_byte, err_msg.end_byte).strip(b"()")
|
||||
res = b"CS_ASSERT(0 && " + err_msg + b")"
|
||||
return res
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class MethodToFunction(Patch):
|
||||
"""
|
||||
Removes the qualified identifier of the class from method definitions.
|
||||
Translating them to functions.
|
||||
|
||||
Patch void CLASS::METHOD_NAME(...) {...}
|
||||
to void METHOD_NAME(...) {...}
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_declarator"
|
||||
" (qualified_identifier"
|
||||
" (namespace_identifier)"
|
||||
" (identifier) @method_name"
|
||||
" )"
|
||||
" (parameter_list) @param_list"
|
||||
") @method_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "method_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
name = captures[1][0]
|
||||
parameter_list = captures[2][0]
|
||||
name = get_text(src, name.start_byte, name.end_byte)
|
||||
parameter_list = get_text(
|
||||
src, parameter_list.start_byte, parameter_list.end_byte
|
||||
)
|
||||
res = name + parameter_list
|
||||
return res
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class MethodTypeQualifier(Patch):
|
||||
"""
|
||||
Patch Removes type qualifiers like "const" etc. from methods.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(function_declarator"
|
||||
" (["
|
||||
" (qualified_identifier)"
|
||||
" (identifier)"
|
||||
" ]) @id"
|
||||
" (parameter_list) @param_list"
|
||||
" (type_qualifier)"
|
||||
")"
|
||||
"@method_type_qualifier"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "method_type_qualifier"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
identifier = captures[1][0]
|
||||
parameter_list = captures[2][0]
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
p_list = get_text(src, parameter_list.start_byte, parameter_list.end_byte)
|
||||
res = identifier + p_list
|
||||
return res
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class NamespaceAnon(Patch):
|
||||
"""
|
||||
Patch namespace {CONTENT}
|
||||
to CONTENT
|
||||
|
||||
Only for anonymous or llvm namespaces
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(namespace_definition"
|
||||
" (declaration_list) @decl_list"
|
||||
") @namespace_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "namespace_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
decl_list = captures[1][0]
|
||||
dl = get_text(src, decl_list.start_byte, decl_list.end_byte).strip(b"{}")
|
||||
return dl
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import (
|
||||
get_text,
|
||||
namespace_enum,
|
||||
namespace_fcn_def,
|
||||
namespace_struct,
|
||||
)
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class NamespaceArch(Patch):
|
||||
"""
|
||||
Patch namespace ArchSpecificNamespace {CONTENT}
|
||||
to CONTENT
|
||||
|
||||
Patches namespaces specific to architecture. This needs to patch enums and functions within this namespace.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(namespace_definition"
|
||||
" (namespace_identifier)"
|
||||
" (declaration_list) @decl_list"
|
||||
") @namespace_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "namespace_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
namespace = captures[0][0]
|
||||
decl_list = captures[1][0]
|
||||
namespace_id = get_text(
|
||||
src,
|
||||
namespace.named_children[0].start_byte,
|
||||
namespace.named_children[0].end_byte,
|
||||
)
|
||||
|
||||
# We need to prepend the namespace id to all enum members, function declarators and struct types.
|
||||
# Because in the generated files they are accessed via NAMESPACE::X which becomes NAMESPACE_X.
|
||||
res = b""
|
||||
for d in decl_list.named_children:
|
||||
match d.type:
|
||||
case "enum_specifier":
|
||||
res += namespace_enum(src, namespace_id, d) + b";\n\n"
|
||||
case "declaration" | "function_definition":
|
||||
res += namespace_fcn_def(src, namespace_id, d) + b"\n\n"
|
||||
case "struct_specifier":
|
||||
res += namespace_struct(src, namespace_id, d) + b";\n\n"
|
||||
case _:
|
||||
res += get_text(src, d.start_byte, d.end_byte) + b"\n"
|
||||
return (
|
||||
b"// CS namespace begin: "
|
||||
+ namespace_id
|
||||
+ b"\n\n"
|
||||
+ res
|
||||
+ b"// CS namespace end: "
|
||||
+ namespace_id
|
||||
+ b"\n\n"
|
||||
)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class NamespaceLLVM(Patch):
|
||||
"""
|
||||
Patch namespace llvm {CONTENT}
|
||||
to CONTENT
|
||||
|
||||
Only for anonymous or llvm namespaces
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(namespace_definition"
|
||||
' (namespace_identifier) @id (#eq? @id "llvm")'
|
||||
" (declaration_list) @decl_list"
|
||||
") @namespace_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "namespace_def"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
decl_list = captures[2][0]
|
||||
dl = get_text(src, decl_list.start_byte, decl_list.end_byte).strip(b"{}")
|
||||
return dl
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class OutStreamParam(Patch):
|
||||
"""
|
||||
Patches the parameter list only:
|
||||
|
||||
Patch void function(int a, raw_ostream &OS)
|
||||
to void function(int a, SStream *OS)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_list"
|
||||
" (_)*"
|
||||
" (parameter_declaration"
|
||||
' ((type_identifier) @tid (#eq? @tid "raw_ostream"))'
|
||||
" (_)"
|
||||
" )"
|
||||
" (_)*"
|
||||
") @ostream_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "ostream_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
param_list = list()
|
||||
for param in captures[0][0].named_children:
|
||||
p_text = get_text(src, param.start_byte, param.end_byte)
|
||||
if b"raw_ostream" in p_text:
|
||||
p_text = p_text.replace(b"raw_ostream", b"SStream").replace(b"&", b"*")
|
||||
param_list.append(p_text)
|
||||
res = b"(" + b", ".join(param_list) + b")"
|
||||
return res
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Override(Patch):
|
||||
"""
|
||||
Patch function(args) override
|
||||
to function(args)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(function_declarator "
|
||||
" ((field_identifier) @declarator)"
|
||||
" ((parameter_list) @parameter_list)"
|
||||
' ((virtual_specifier) @specifier (#eq? @specifier "override"))'
|
||||
") @override"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "override"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get function name
|
||||
declarator: Node = captures[1][0]
|
||||
# Get parameter list
|
||||
parameter_list: Node = captures[2][0]
|
||||
decl = get_text(src, declarator.start_byte, declarator.end_byte)
|
||||
params = get_text(src, parameter_list.start_byte, parameter_list.end_byte)
|
||||
return decl + params
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
|
||||
class Patch:
|
||||
priority: int = None
|
||||
|
||||
def __init__(self, priority: int = 0):
|
||||
self.priority = priority
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
"""
|
||||
Returns a search pattern for the syntax tree of the C++ file.
|
||||
The search pattern must be formed according to:
|
||||
https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries
|
||||
|
||||
Also, each pattern needs to be assigned a name in order to work.
|
||||
See: https://github.com/tree-sitter/py-tree-sitter/issues/77
|
||||
|
||||
:return: The search pattern which matches a part in the syntax tree which will be patched.
|
||||
"""
|
||||
log.fatal("Method must be overloaded.")
|
||||
exit(1)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
"""
|
||||
:return: The name of the capture which matches the complete syntax to be patched.
|
||||
"""
|
||||
log.fatal("Method must be overloaded.")
|
||||
exit(1)
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
"""
|
||||
Patches the given subtree accordingly and returns the patch as string.
|
||||
|
||||
:param src: The source code currently patched.
|
||||
:param captures: The subtree and its name which needs to be patched.
|
||||
:param **kwargs: Additional arguments the Patch might need.
|
||||
:return: The patched version of the code.
|
||||
"""
|
||||
log.fatal("Method must be overloaded.")
|
||||
exit(1)
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class PredicateBlockFunctions(Patch):
|
||||
"""
|
||||
Patch VPTBlock.instrInVPTBlock()
|
||||
to VPTBlock_instrInVPTBlock(&(MI->csh->VPTBlock))
|
||||
|
||||
And other functions of VPTBlock and ITBlock
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
' ((identifier) @block_var (#match? @block_var "[VI][PT]T?Block"))'
|
||||
" ((field_identifier) @field_id)"
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @block_fcns"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "block_fcns"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
block_var = captures[1][0]
|
||||
fcn_id = captures[2][0]
|
||||
args = captures[3][0]
|
||||
block_var_text = get_text(src, block_var.start_byte, block_var.end_byte)
|
||||
fcn_id_text = get_text(src, fcn_id.start_byte, fcn_id.end_byte)
|
||||
args_text = get_text(src, args.start_byte, args.end_byte)
|
||||
mcinst_var: bytes = get_MCInst_var_name(src, block_var)
|
||||
|
||||
a = b"&(" + mcinst_var + b"->csh->" + block_var_text + b")"
|
||||
args_text = args_text.strip(b"()")
|
||||
if args_text:
|
||||
a += b"," + args_text
|
||||
return block_var_text + b"_" + fcn_id_text + b"(" + a + b")"
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class PrintAnnotation(Patch):
|
||||
"""
|
||||
Removes printAnnotation(...) calls.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "printAnnotation")'
|
||||
" (argument_list)"
|
||||
")) @print_annotation"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "print_annotation"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class PrintRegImmShift(Patch):
|
||||
"""
|
||||
Patch printRegImmShift(...)
|
||||
to printRegImmShift(MI, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
self.apply_only_to = {"files": ["ARMInstPrinter.cpp"], "archs": list()}
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression ("
|
||||
' (identifier) @fcn_name (#eq? @fcn_name "printRegImmShift")'
|
||||
" ((argument_list) @arg_list)"
|
||||
")) @print_call"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "print_call"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
call: Node = captures[0][0]
|
||||
mcinst_var = get_MCInst_var_name(src, call)
|
||||
params = captures[2][0]
|
||||
params = get_text(src, params.start_byte, params.end_byte)
|
||||
return b"printRegImmShift(" + mcinst_var + b", " + params.strip(b"(")
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class QualifiedIdentifier(Patch):
|
||||
"""
|
||||
Patch NAMESPACE::ID
|
||||
to NAMESPACE_ID
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "(qualified_identifier) @qualified_id"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "qualified_id"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
if len(captures[0][0].named_children) > 1:
|
||||
identifier = captures[0][0].named_children[1]
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
namespace = captures[0][0].named_children[0]
|
||||
namespace = get_text(src, namespace.start_byte, namespace.end_byte)
|
||||
else:
|
||||
# The namespace can be omitted. E.g. std::transform(..., ::tolower)
|
||||
namespace = b""
|
||||
identifier = captures[0][0].named_children[0]
|
||||
identifier = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
match (namespace, identifier):
|
||||
case (b"std", b"size"):
|
||||
return b"sizeof"
|
||||
case _:
|
||||
return namespace + b"_" + identifier
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class ReferencesDecl(Patch):
|
||||
"""
|
||||
Patch TYPE &Param
|
||||
to TYPE *Param
|
||||
|
||||
Param is optional
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"["
|
||||
"(reference_declarator)"
|
||||
"(type_identifier) (abstract_reference_declarator)"
|
||||
"] @reference_decl"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "reference_decl"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
ref_decl: Node = captures[0][0]
|
||||
ref_decl_text = get_text(src, ref_decl.start_byte, ref_decl.end_byte)
|
||||
|
||||
res = re.sub(rb"&", b"*", ref_decl_text)
|
||||
return res
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class RegClassContains(Patch):
|
||||
"""
|
||||
Patch ...getRegClass(...).contains(Reg)
|
||||
to MCRegisterClass_contains(...getRegClass(...), Reg)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression"
|
||||
" (field_expression"
|
||||
' ((_) @reg_class (#match? @reg_class ".+getRegClass.+"))'
|
||||
' ((field_identifier) @field_id (#eq? @field_id "contains"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @reg_class_contains"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "reg_class_contains"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
reg_class_getter: Node = get_capture_node(captures, "reg_class")
|
||||
arg_list: Node = get_capture_node(captures, "arg_list")
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
||||
reg_class = get_text(
|
||||
src, reg_class_getter.start_byte, reg_class_getter.end_byte
|
||||
)
|
||||
res = b"MCRegisterClass_contains(" + reg_class + b", " + args + b")"
|
||||
return res
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class STIArgument(Patch):
|
||||
"""
|
||||
Patch printSomeOperand(MI, NUM, STI, NUM)
|
||||
to printSomeOperand(MI, NUM, NUM)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return '(argument_list (_) (_) (_)? ((identifier) @id (#eq? @id "STI")) (_)) @sti_arg'
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "sti_arg"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
param_list = list()
|
||||
for param in captures[0][0].named_children:
|
||||
p_text = get_text(src, param.start_byte, param.end_byte)
|
||||
if b"STI" in p_text:
|
||||
continue
|
||||
param_list.append(p_text)
|
||||
res = b"(" + b", ".join(param_list) + b")"
|
||||
return res
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class STIFeatureBits(Patch):
|
||||
"""
|
||||
Patch STI.getFeatureBits()[ARCH::FLAG]
|
||||
to ARCH_getFeatureBits(Inst->csh->mode, ARCH::FLAG)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, arch: bytes):
|
||||
self.arch = arch
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
# Search for featureBits usage.
|
||||
return (
|
||||
"(subscript_expression "
|
||||
" (call_expression"
|
||||
" (field_expression"
|
||||
" (identifier)"
|
||||
' ((field_identifier) @fid (#eq? @fid "getFeatureBits"))'
|
||||
" )"
|
||||
" (argument_list)"
|
||||
" )"
|
||||
" (subscript_argument_list ((qualified_identifier) @flag))"
|
||||
") @sti_feature_bits"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "sti_feature_bits"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get flag name of feature bit.
|
||||
qualified_id: Node = captures[2][0]
|
||||
flag = get_text(src, qualified_id.start_byte, qualified_id.end_byte)
|
||||
return self.arch + b"_getFeatureBits(Inst->csh->mode, " + flag + b")"
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class SubtargetInfoParam(Patch):
|
||||
"""
|
||||
Patch Removes MCSubtargetInfo &STI parameter
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_list"
|
||||
" (_)*"
|
||||
" (parameter_declaration"
|
||||
' ((type_identifier) @tid (#eq? @tid "MCSubtargetInfo"))'
|
||||
" (_)"
|
||||
" )"
|
||||
" (_)*"
|
||||
") @subtarget_info_param"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "subtarget_info_param"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
param_list = list()
|
||||
for param in captures[0][0].named_children:
|
||||
p_text = get_text(src, param.start_byte, param.end_byte)
|
||||
if b"MCSubtargetInfo" in p_text:
|
||||
continue
|
||||
param_list.append(p_text)
|
||||
res = b"(" + b", ".join(param_list) + b")"
|
||||
return res
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class SetOpcode(Patch):
|
||||
"""
|
||||
Patch Inst.setOpcode(...)
|
||||
to MCInst_setOpcode(Inst, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (field_expression ("
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id (#eq? @field_id "setOpcode")))'
|
||||
" )"
|
||||
" (argument_list) @arg_list"
|
||||
") @set_opcode"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "set_opcode"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Instruction variable
|
||||
inst_var: Node = captures[1][0]
|
||||
arg_list: Node = captures[3][0]
|
||||
|
||||
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte)
|
||||
if args != b"()":
|
||||
args = b", " + args
|
||||
else:
|
||||
args = b""
|
||||
return b"MCInst_setOpcode(" + inst + args + b")"
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
|
||||
class SignExtend(Patch):
|
||||
"""
|
||||
Patch SignExtend32<A>(...)
|
||||
to SignExtend32(..., A)
|
||||
|
||||
Same for SignExtend64
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (template_function"
|
||||
' ((identifier) @name (#match? @name "SignExtend(32|64)"))'
|
||||
" ((template_argument_list) @templ_args)"
|
||||
" )"
|
||||
" ((argument_list) @fcn_args)"
|
||||
") @sign_extend"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "sign_extend"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
sign_extend: Node = captures[1][0]
|
||||
templ_args: Node = captures[2][0]
|
||||
fcn_args: Node = captures[3][0]
|
||||
|
||||
name = get_text(src, sign_extend.start_byte, sign_extend.end_byte)
|
||||
t_args = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
||||
t_args = b", ".join(TemplateCollector.templ_params_to_list(t_args))
|
||||
f_args = get_text(src, fcn_args.start_byte, fcn_args.end_byte)
|
||||
return name + b"(" + f_args + b", " + t_args + b")"
|
||||
@@ -0,0 +1,35 @@
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class Size(Patch):
|
||||
"""
|
||||
Patch Bytes.size()
|
||||
to BytesLen
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
q = (
|
||||
"(call_expression "
|
||||
" (field_expression"
|
||||
" ((identifier) @inst_var)"
|
||||
' ((field_identifier) @field_id_op (#eq? @field_id_op "size"))'
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @size"
|
||||
)
|
||||
return q
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "size"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
# Get operand variable name (Bytes, ArrayRef)
|
||||
op_var: Node = captures[1][0]
|
||||
op = get_text(src, op_var.start_byte, op_var.end_byte)
|
||||
return op + b"Len"
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class SizeAssignment(Patch):
|
||||
"""
|
||||
Patch Size = <num>
|
||||
to *Size = <num>
|
||||
|
||||
if Size is a reference.
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(assignment_expression"
|
||||
' ((identifier) @id (#eq? @id "Size"))'
|
||||
") @assign"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "assign"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
assign = captures[0][0]
|
||||
assign_text = get_text(src, assign.start_byte, assign.end_byte)
|
||||
|
||||
param_list = get_function_params_of_node(assign)
|
||||
if not param_list:
|
||||
return assign_text
|
||||
|
||||
for p in param_list.named_children:
|
||||
p_text = get_text(src, p.start_byte, p.end_byte)
|
||||
if b"&Size" in p_text:
|
||||
return re.sub(b"Size", b"*Size", assign_text)
|
||||
|
||||
return assign_text
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text, get_text_from_node
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class StreamOperations(Patch):
|
||||
"""
|
||||
Patch OS << ...
|
||||
to SStream_concat(OS, ...)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(expression_statement"
|
||||
" (binary_expression"
|
||||
" ((binary_expression)"
|
||||
' "<<"'
|
||||
" (_))*"
|
||||
" ) @bin_expr"
|
||||
") @stream"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "stream"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
bin_expr = captures[1][0]
|
||||
# Extract operands passed to the stream into a list.
|
||||
ops = list()
|
||||
while bin_expr.type == "binary_expression":
|
||||
ops.append(bin_expr.named_children[1])
|
||||
bin_expr = bin_expr.named_children[0]
|
||||
s_name = get_text(src, bin_expr.start_byte, bin_expr.end_byte)
|
||||
# We added the operands from right to left.
|
||||
# We reversing it so the left most operand comes first.
|
||||
ops.reverse()
|
||||
|
||||
res = b""
|
||||
# Capstone uses the following functions to copy the strings to a buffer:
|
||||
# SStream_concat - Copies multiple strings.
|
||||
# SStream_concat1 - Copies a char.
|
||||
# SStream_concat0 - Copies a string and null terminates the buffer.
|
||||
last_op: Node = ops[-1]
|
||||
op: Node = ops[0]
|
||||
string_ops = list()
|
||||
i = 0
|
||||
while op != last_op:
|
||||
if op.type == "char_literal":
|
||||
if len(string_ops) != 0:
|
||||
# Make a SStream_concat call with all string literals collected before.
|
||||
res += (
|
||||
b"SStream_concat("
|
||||
+ s_name
|
||||
+ b', "'
|
||||
+ b"%s" * len(string_ops)
|
||||
+ b'", '
|
||||
+ b", ".join(
|
||||
[
|
||||
get_text(src, o.start_byte, o.end_byte)
|
||||
for o in string_ops
|
||||
]
|
||||
)
|
||||
+ b");\n"
|
||||
)
|
||||
string_ops.clear()
|
||||
res += (
|
||||
b"SStream_concat1("
|
||||
+ s_name
|
||||
+ b", "
|
||||
+ get_text(src, op.start_byte, op.end_byte)
|
||||
+ b");\n"
|
||||
)
|
||||
else:
|
||||
string_ops.append(op)
|
||||
i += 1
|
||||
op = ops[i]
|
||||
|
||||
if len(string_ops) != 0:
|
||||
res += (
|
||||
b"SStream_concat("
|
||||
+ s_name
|
||||
+ b', "'
|
||||
+ b"%s" * len(string_ops)
|
||||
+ b'", '
|
||||
+ b", ".join(
|
||||
[get_text(src, o.start_byte, o.end_byte) for o in string_ops]
|
||||
)
|
||||
+ b");\n"
|
||||
)
|
||||
string_ops.clear()
|
||||
|
||||
last_op_text = get_text(src, last_op.start_byte, last_op.end_byte)
|
||||
if last_op.type == "char_literal":
|
||||
res += (
|
||||
b"SStream_concat0("
|
||||
+ s_name
|
||||
+ b", "
|
||||
+ last_op_text.replace(b"'", b'"')
|
||||
+ b");\n"
|
||||
)
|
||||
elif last_op.type == "identifier":
|
||||
queue_str = f"""
|
||||
(declaration (
|
||||
(primitive_type) @typ
|
||||
(init_declarator
|
||||
(identifier) @ident (#eq? @ident "{last_op_text.decode("utf8")}")
|
||||
)
|
||||
)) @decl
|
||||
"""
|
||||
query = kwargs["ts_cpp_lang"].query(queue_str)
|
||||
root_node = kwargs["tree"].root_node
|
||||
query_result = list(
|
||||
filter(
|
||||
lambda x: "typ" in x[1],
|
||||
query.matches(root_node),
|
||||
)
|
||||
)
|
||||
if len(query_result) == 0:
|
||||
res += b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
||||
else:
|
||||
typ = get_text_from_node(src, query_result[0][1]["typ"][-1])
|
||||
match typ:
|
||||
case b"int":
|
||||
res += b"printInt32(" + s_name + b", " + last_op_text + b");"
|
||||
case b"int64_t":
|
||||
res += b"printInt64(" + s_name + b", " + last_op_text + b");"
|
||||
case _:
|
||||
res += (
|
||||
b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
||||
)
|
||||
else:
|
||||
res += b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
||||
stream = captures[0][0]
|
||||
if len(ops) > 1 and stream.parent.type in ["if_statement"]:
|
||||
# If statements without {} brackets might execute a single line `OS << ...;` statement.
|
||||
# Which we then translate into multiple lines. For this case we need to add the brackets.
|
||||
res = b"{ " + res + b" }"
|
||||
return res
|
||||
Vendored
+84
@@ -0,0 +1,84 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import parse_function_capture
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import (
|
||||
TemplateCollector,
|
||||
TemplateRefInstance,
|
||||
)
|
||||
|
||||
|
||||
class TemplateDeclaration(Patch):
|
||||
"""
|
||||
Patch template<A, B>
|
||||
RET_TYPE TemplateFunction(...);
|
||||
|
||||
to #define DECLARE_TemplateFunction_A_B \
|
||||
RET_TYPE CONCAT(TemplateFunction, CONCAT(A, B))(...);
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, template_collector: TemplateCollector):
|
||||
self.collector: TemplateCollector = template_collector
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(template_declaration"
|
||||
" ((template_parameter_list) @templ_params)"
|
||||
" (declaration"
|
||||
" ((storage_class_specifier)* @storage_class_id)"
|
||||
" ([(type_identifier)(primitive_type)] @type_id)"
|
||||
" (function_declarator"
|
||||
" ((identifier) @fcn_name)"
|
||||
" ((parameter_list) @fcn_params)"
|
||||
" )"
|
||||
" )"
|
||||
") @template_decl"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_decl"
|
||||
|
||||
def get_patch(
|
||||
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
|
||||
) -> bytes:
|
||||
t_params, sc, tid, f_name, f_params, _ = parse_function_capture(captures, src)
|
||||
if f_name in self.collector.templates_with_arg_deduction:
|
||||
return sc + tid + b" " + f_name + f_params + b";"
|
||||
|
||||
declaration = (
|
||||
b"#define DECLARE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
|
||||
)
|
||||
declaration += (
|
||||
sc
|
||||
+ b" "
|
||||
+ tid
|
||||
+ b" "
|
||||
+ TemplateCollector.get_macro_c_call(f_name, t_params, f_params)
|
||||
+ b";"
|
||||
)
|
||||
declaration = declaration.replace(b"\n", b" \\\n") + b"\n"
|
||||
|
||||
template_instance: TemplateRefInstance
|
||||
declared_implementations = list()
|
||||
if f_name not in self.collector.template_refs:
|
||||
self.collector.log_missing_ref_and_exit(f_name)
|
||||
|
||||
for template_instance in self.collector.template_refs[f_name]:
|
||||
d = (
|
||||
b"DECLARE_"
|
||||
+ f_name
|
||||
+ b"("
|
||||
+ b", ".join(template_instance.get_args_for_decl())
|
||||
+ b");\n"
|
||||
)
|
||||
if d in declared_implementations:
|
||||
continue
|
||||
declared_implementations.append(d)
|
||||
declaration += d
|
||||
return declaration
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
import re
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import parse_function_capture
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import (
|
||||
TemplateCollector,
|
||||
TemplateRefInstance,
|
||||
)
|
||||
|
||||
|
||||
class TemplateDefinition(Patch):
|
||||
"""
|
||||
Patch template<A, B>
|
||||
RET_TYPE TemplateFunction(...) {...}
|
||||
|
||||
to #define DEFINE_TemplateFunction_A_B \
|
||||
RET_TYPE CONCAT(TemplateFunction, CONCAT(A, B))(...) {...}
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int, template_collector: TemplateCollector):
|
||||
self.collector: TemplateCollector = template_collector
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(template_declaration"
|
||||
" ((template_parameter_list) @templ_params)"
|
||||
" (function_definition"
|
||||
" ((storage_class_specifier)* @storage_class_id)"
|
||||
" ([(type_identifier)(primitive_type)] @type_id)"
|
||||
" (function_declarator"
|
||||
" ((identifier) @fcn_name)"
|
||||
" ((parameter_list) @fcn_params)"
|
||||
" )"
|
||||
" ((compound_statement) @compound)"
|
||||
" )"
|
||||
") @template_def"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_def"
|
||||
|
||||
def get_patch(
|
||||
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
|
||||
) -> bytes:
|
||||
t_params, sc, tid, f_name, f_params, f_compound = parse_function_capture(
|
||||
captures, src
|
||||
)
|
||||
if f_name in self.collector.templates_with_arg_deduction:
|
||||
return sc + tid + b" " + f_name + f_params + f_compound
|
||||
|
||||
definition = b"#define DEFINE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
|
||||
definition += (
|
||||
sc
|
||||
+ b" "
|
||||
+ tid
|
||||
+ b" "
|
||||
+ TemplateCollector.get_macro_c_call(f_name, t_params, f_params)
|
||||
+ f_compound
|
||||
)
|
||||
# Remove // comments
|
||||
definition = re.sub(b" *//.*", b"", definition)
|
||||
definition = definition.replace(b"\n", b" \\\n") + b"\n"
|
||||
|
||||
template_instance: TemplateRefInstance
|
||||
declared_implementations = list()
|
||||
if f_name not in self.collector.template_refs:
|
||||
self.collector.log_missing_ref_and_exit(f_name)
|
||||
|
||||
for template_instance in self.collector.template_refs[f_name]:
|
||||
d = (
|
||||
b"DEFINE_"
|
||||
+ f_name
|
||||
+ b"("
|
||||
+ b", ".join(template_instance.get_args_for_decl())
|
||||
+ b");\n"
|
||||
)
|
||||
if d in declared_implementations:
|
||||
continue
|
||||
declared_implementations.append(d)
|
||||
definition += d
|
||||
return definition
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
import logging as log
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class TemplateParamDecl(Patch):
|
||||
"""
|
||||
Example:
|
||||
|
||||
Patch ArrayRef<uint8_t> x
|
||||
to const uint8_t *x, size_t xLen
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(parameter_declaration"
|
||||
" (template_type"
|
||||
" (type_identifier) @templ_type"
|
||||
" (template_argument_list) @arg_list"
|
||||
" )"
|
||||
" (identifier) @param_id"
|
||||
") @template_param_decl"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_param_decl"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
template_type = captures[1][0]
|
||||
arg_list = captures[2][0]
|
||||
param_id = captures[3][0]
|
||||
templ_type = get_text(src, template_type.start_byte, template_type.end_byte)
|
||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte)
|
||||
p_id = get_text(src, param_id.start_byte, param_id.end_byte)
|
||||
|
||||
if templ_type == b"ArrayRef":
|
||||
res = (
|
||||
b"const "
|
||||
+ args.strip(b"<>")
|
||||
+ b" *"
|
||||
+ p_id
|
||||
+ b", size_t "
|
||||
+ p_id
|
||||
+ b"Len"
|
||||
)
|
||||
return res
|
||||
log.fatal(f"Template type {templ_type} not handled as parameter")
|
||||
exit(1)
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
|
||||
class TemplateRefs(Patch):
|
||||
"""
|
||||
Patch TemplateFunction<A, B>
|
||||
to CONCAT(TemplateFunction, CONCAT(A, B))
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(template_function"
|
||||
" ((identifier) @name)"
|
||||
" ((template_argument_list) @templ_args)"
|
||||
") @template_refs"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "template_refs"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
tc: Node = captures[1][0]
|
||||
templ_args: Node = captures[2][0]
|
||||
|
||||
name = get_text(src, tc.start_byte, tc.end_byte)
|
||||
t_params = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
||||
if name == b"static_cast" or name == b"dyn_cast":
|
||||
return t_params.replace(b"<", b"(").replace(b">", b")")
|
||||
t_params_list = TemplateCollector.templ_params_to_list(t_params)
|
||||
res = TemplateCollector.get_macro_c_call(name, t_params_list)
|
||||
return res
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class UseMarkup(Patch):
|
||||
"""
|
||||
Patch UseMarkup
|
||||
to getUseMarkup()
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return '((identifier) @use_markup (#eq? @use_markup "UseMarkup"))'
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "use_markup"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b"getUseMarkup()"
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
|
||||
|
||||
class UsingDeclaration(Patch):
|
||||
"""
|
||||
Patch Removes declarations with the keyword "using"
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return "([(using_declaration) (alias_declaration)]) @using_declaration"
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "using_declaration"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
return b""
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from tree_sitter import Node
|
||||
|
||||
from autosync.cpptranslator.patches.Helper import get_text
|
||||
from autosync.cpptranslator.patches.Patch import Patch
|
||||
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||
|
||||
|
||||
class IsUInt(Patch):
|
||||
"""
|
||||
Patch isUInt|isInt<N>(...)
|
||||
to isUInt|isInt(..., N)
|
||||
"""
|
||||
|
||||
def __init__(self, priority: int):
|
||||
super().__init__(priority)
|
||||
|
||||
def get_search_pattern(self) -> str:
|
||||
return (
|
||||
"(call_expression"
|
||||
" (template_function"
|
||||
' ((identifier) @id (#match? @id "isUInt|isInt"))'
|
||||
" ((template_argument_list) @templ_args)"
|
||||
" )"
|
||||
" ((argument_list) @arg_list)"
|
||||
") @is_u_int"
|
||||
)
|
||||
|
||||
def get_main_capture_name(self) -> str:
|
||||
return "is_u_int"
|
||||
|
||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||
identifier: Node = captures[1][0]
|
||||
templ_args: Node = captures[2][0]
|
||||
args_list: Node = captures[3][0]
|
||||
|
||||
name = get_text(src, identifier.start_byte, identifier.end_byte)
|
||||
targs = get_text(src, templ_args.start_byte, templ_args.end_byte).strip(b"<>")
|
||||
args = get_text(src, args_list.start_byte, args_list.end_byte).strip(b"()")
|
||||
|
||||
res = name + b"N(" + targs + b", " + args + b")"
|
||||
|
||||
return res
|
||||
+4544
File diff suppressed because it is too large
Load Diff
+20
@@ -0,0 +1,20 @@
|
||||
from tree_sitter import Node, Query
|
||||
|
||||
|
||||
# Queries for the given pattern and converts the query back to the tree-siter v22.3 format.
|
||||
# Which is: A list of tuples where the first element is the
|
||||
# Node of the capture and the second one is the name.
|
||||
def query_captures_22_3(query: Query, node: Node) -> list[tuple[Node, str]]:
|
||||
result = list()
|
||||
captures = query.captures(node)
|
||||
# Captures are no longer sorted by start point.
|
||||
captures_sorted = dict()
|
||||
nodes: list[Node]
|
||||
for name, nodes in captures.items():
|
||||
captures_sorted[name] = sorted(nodes, key=lambda n: n.start_point)
|
||||
while len(captures_sorted) != 0:
|
||||
for name, nodes in captures_sorted.items():
|
||||
node = nodes.pop(0)
|
||||
result.append((node, name))
|
||||
captures_sorted = {k: l for k, l in captures_sorted.items() if len(l) != 0}
|
||||
return result
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"inc_tables": [
|
||||
{
|
||||
"name": "Disassembler",
|
||||
"tblgen_arg": "--gen-disassembler",
|
||||
"inc_name": "DisassemblerTables",
|
||||
"only_arch": [],
|
||||
"lang": ["CCS", "C++"]
|
||||
},
|
||||
{
|
||||
"name": "AsmWriter",
|
||||
"tblgen_arg": "--gen-asm-writer",
|
||||
"inc_name": "AsmWriter",
|
||||
"only_arch": [],
|
||||
"lang": ["CCS", "C++"]
|
||||
},
|
||||
{
|
||||
"name": "RegisterInfo",
|
||||
"tblgen_arg": "--gen-register-info",
|
||||
"inc_name": "RegisterInfo",
|
||||
"only_arch": [],
|
||||
"lang": ["CCS"]
|
||||
},
|
||||
{
|
||||
"name": "InstrInfo",
|
||||
"tblgen_arg": "--gen-instr-info",
|
||||
"inc_name": "InstrInfo",
|
||||
"only_arch": [],
|
||||
"lang": ["CCS"]
|
||||
},
|
||||
{
|
||||
"name": "SubtargetInfo",
|
||||
"tblgen_arg": "--gen-subtarget",
|
||||
"inc_name": "SubtargetInfo",
|
||||
"only_arch": [],
|
||||
"lang": ["CCS"]
|
||||
},
|
||||
{
|
||||
"name": "Mapping",
|
||||
"tblgen_arg": "--gen-asm-matcher",
|
||||
"inc_name": "",
|
||||
"only_arch": [],
|
||||
"lang": ["CCS"]
|
||||
},
|
||||
{
|
||||
"name": "SystemOperand",
|
||||
"tblgen_arg": "--gen-searchable-tables",
|
||||
"inc_name": "",
|
||||
"only_arch": ["AArch64", "ARM", "Sparc"],
|
||||
"lang": ["CCS"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<!--
|
||||
Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
SPDX-License-Identifier: BSD-3
|
||||
-->
|
||||
|
||||
lit configurations for MC regression test generation.
|
||||
As an introduction see: https://medium.com/@mshockwave/using-llvm-lit-out-of-tree-5cddada85a78 ([archived](https://web.archive.org/web/20240421091240/https://medium.com/@mshockwave/using-llvm-lit-out-of-tree-5cddada85a78))
|
||||
@@ -0,0 +1,14 @@
|
||||
# Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from autosync.PathVarHandler import PathVarHandler
|
||||
import lit.formats
|
||||
|
||||
config.name = "Generate Capstone MC regression tests"
|
||||
config.test_format = lit.formats.ShTest(True)
|
||||
|
||||
config.suffixes = [".txt", ".s"]
|
||||
|
||||
config.excludes = ["Inputs", "CMakeLists.txt", "README.txt", "LICENSE.txt"]
|
||||
|
||||
config.test_source_root = PathVarHandler().get_path("{LLVM_LIT_TEST_DIR}")
|
||||
@@ -0,0 +1,16 @@
|
||||
# Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
# SPDX-License-Identifier: BSD-3
|
||||
|
||||
from autosync.Targets import TARGETS_LLVM_NAMING
|
||||
from autosync.PathVarHandler import PathVarHandler
|
||||
from pathlib import Path
|
||||
|
||||
import lit.llvm
|
||||
|
||||
lit.llvm.initialize(lit_config, config)
|
||||
|
||||
config.llvm_src_root = str(PathVarHandler().get_path("{LLVM_ROOT}").absolute())
|
||||
config.root.targets = " ".join(TARGETS_LLVM_NAMING)
|
||||
|
||||
lit_cfg_dir = PathVarHandler().get_path("{LLVM_LIT_TEST_DIR}")
|
||||
lit_config.load_config(config, lit_cfg_dir.joinpath("lit.cfg.py"))
|
||||
@@ -0,0 +1,151 @@
|
||||
{
|
||||
"use_assembly_tests": [
|
||||
"Xtensa",
|
||||
"Sparc"
|
||||
],
|
||||
"exclude_disassembly_tests": [
|
||||
"Xtensa"
|
||||
],
|
||||
"unify_test_cases": [
|
||||
"ARM"
|
||||
],
|
||||
"additional_mattr":
|
||||
{
|
||||
"AArch64":
|
||||
[
|
||||
"+all"
|
||||
]
|
||||
},
|
||||
"mandatory_options":
|
||||
{
|
||||
"Mips":
|
||||
[
|
||||
"CS_OPT_SYNTAX_NOREGNAME"
|
||||
],
|
||||
"PPC":
|
||||
[
|
||||
"CS_OPT_ONLY_OFFSET_BRANCH",
|
||||
"CS_OPT_SYNTAX_NOREGNAME"
|
||||
|
||||
],
|
||||
"ARM":
|
||||
[
|
||||
"CS_OPT_ONLY_OFFSET_BRANCH"
|
||||
],
|
||||
"AArch64":
|
||||
[
|
||||
"CS_OPT_ONLY_OFFSET_BRANCH"
|
||||
]
|
||||
},
|
||||
"default_endianess":
|
||||
{
|
||||
"SystemZ": "CS_MODE_BIG_ENDIAN",
|
||||
"PPC": "CS_MODE_BIG_ENDIAN",
|
||||
"Sparc": "CS_MODE_BIG_ENDIAN"
|
||||
},
|
||||
"remove_options":
|
||||
{
|
||||
"Mips":
|
||||
[
|
||||
"mips",
|
||||
"dsp",
|
||||
"dspr2",
|
||||
"dspr3",
|
||||
"mips3d",
|
||||
"msa",
|
||||
"eva",
|
||||
"crc",
|
||||
"virt",
|
||||
"ginv",
|
||||
"fp64",
|
||||
"+virt",
|
||||
"mt"
|
||||
],
|
||||
"PPC": [
|
||||
"powerpc64-unknown-linux-gnu"
|
||||
]
|
||||
},
|
||||
"replace_option_map":
|
||||
{
|
||||
"Mips":
|
||||
{
|
||||
"mips-unknown-linux": ["CS_MODE_BIG_ENDIAN"],
|
||||
"mips-unknown-linux-gnu": ["CS_MODE_BIG_ENDIAN"],
|
||||
"mips32-unknown-linux": ["CS_MODE_BIG_ENDIAN"],
|
||||
"mips64-unknown-linux": ["CS_MODE_BIG_ENDIAN"],
|
||||
"mips64-unknown-linux-gnu": ["CS_MODE_BIG_ENDIAN"],
|
||||
"mips64el-unknown-linux": ["CS_MODE_LITTLE_ENDIAN"],
|
||||
"mips64el-unknown-linux-gnu": ["CS_MODE_LITTLE_ENDIAN"],
|
||||
"mipsel": ["CS_MODE_LITTLE_ENDIAN"],
|
||||
"mipsel-unknown-linux": ["CS_MODE_LITTLE_ENDIAN"],
|
||||
"mipsel-unknown-linux-gnu": ["CS_MODE_LITTLE_ENDIAN"],
|
||||
"mips16": ["CS_MODE_MIPS16"],
|
||||
"mips32": ["CS_MODE_MIPS32"],
|
||||
"mips64": ["CS_MODE_MIPS64"],
|
||||
"micromips": ["CS_MODE_MICRO"],
|
||||
"mips1": ["CS_MODE_MIPS1"],
|
||||
"mips2": ["CS_MODE_MIPS2"],
|
||||
"mips32r2": ["CS_MODE_MIPS32R2"],
|
||||
"mips32r3": ["CS_MODE_MIPS32R3"],
|
||||
"mips32r5": ["CS_MODE_MIPS32R5"],
|
||||
"mips32r6": ["CS_MODE_MIPS32R6"],
|
||||
"mips3": ["CS_MODE_MIPS3"],
|
||||
"mips4": ["CS_MODE_MIPS4"],
|
||||
"mips5": ["CS_MODE_MIPS5"],
|
||||
"mips64r2": ["CS_MODE_MIPS64R2"],
|
||||
"mips64r3": ["CS_MODE_MIPS64R3"],
|
||||
"mips64r5": ["CS_MODE_MIPS64R5"],
|
||||
"mips64r6": ["CS_MODE_MIPS64R6"],
|
||||
"octeon": ["CS_MODE_OCTEON"],
|
||||
"octeon+": ["CS_MODE_OCTEONP"],
|
||||
"nanomips": ["CS_MODE_NANOMIPS"],
|
||||
"nms1": ["CS_MODE_NMS1"],
|
||||
"i7200": ["CS_MODE_I7200"],
|
||||
"mips_nofloat": ["CS_MODE_MIPS_NOFLOAT"],
|
||||
"mips_ptr64": ["CS_MODE_MIPS_PTR64"]
|
||||
},
|
||||
"SystemZ": {
|
||||
"arch8": ["CS_MODE_SYSTEMZ_ARCH8"],
|
||||
"arch9": ["CS_MODE_SYSTEMZ_ARCH9"],
|
||||
"arch10": ["CS_MODE_SYSTEMZ_ARCH10"],
|
||||
"arch11": ["CS_MODE_SYSTEMZ_ARCH11"],
|
||||
"arch12": ["CS_MODE_SYSTEMZ_ARCH12"],
|
||||
"arch13": ["CS_MODE_SYSTEMZ_ARCH13"],
|
||||
"arch14": ["CS_MODE_SYSTEMZ_ARCH14"],
|
||||
"z10": ["CS_MODE_SYSTEMZ_Z10"],
|
||||
"z196": ["CS_MODE_SYSTEMZ_Z196"],
|
||||
"zec12": ["CS_MODE_SYSTEMZ_ZEC12"],
|
||||
"z13": ["CS_MODE_SYSTEMZ_Z13"],
|
||||
"z14": ["CS_MODE_SYSTEMZ_Z14"],
|
||||
"z15": ["CS_MODE_SYSTEMZ_Z15"],
|
||||
"z16": ["CS_MODE_SYSTEMZ_Z16"],
|
||||
"generic": ["CS_MODE_SYSTEMZ_GENERIC"]
|
||||
},
|
||||
"PPC": {
|
||||
"powerpc64-unknown-unknown": ["CS_MODE_BIG_ENDIAN", "CS_MODE_64"],
|
||||
"powerpc64-unknown-linux": ["CS_MODE_BIG_ENDIAN", "CS_MODE_64"],
|
||||
"powerpc64-unknown-aix-gnu": ["CS_MODE_BIG_ENDIAN", "CS_MODE_64", "CS_MODE_AIX_OS"],
|
||||
"powerpc64le-unknown-unknown": ["CS_MODE_LITTLE_ENDIAN", "CS_MODE_64"],
|
||||
"powerpc64-ibm-aix-xcoff": ["CS_MODE_BIG_ENDIAN", "CS_MODE_64", "CS_MODE_AIX_OS"],
|
||||
"powerpc-unknown-aix-gnu": ["CS_MODE_BIG_ENDIAN", "CS_MODE_32", "CS_MODE_AIX_OS"],
|
||||
"pwr7": ["CS_MODE_PWR7"],
|
||||
"pwr8": ["CS_MODE_PWR8"],
|
||||
"pwr9": ["CS_MODE_PWR9"],
|
||||
"pwr10": ["CS_MODE_PWR10"],
|
||||
"pwr10": ["CS_MODE_PWR10"],
|
||||
"future": ["CS_MODE_PPC_ISA_FUTURE"],
|
||||
"modern-aix-as": ["CS_MODE_MODERN_AIX_AS"],
|
||||
"spe": ["CS_MODE_SPE"],
|
||||
"a2": ["CS_MODE_BOOKE"]
|
||||
},
|
||||
"Sparc": {
|
||||
"sparc": ["CS_MODE_BIG_ENDIAN"],
|
||||
"sparc-unknown-linux": ["CS_MODE_BIG_ENDIAN"],
|
||||
"sparc64-linux-gnu": ["CS_MODE_V9"],
|
||||
"sparc64-unknown-linux-gnu": ["CS_MODE_V9"],
|
||||
"sparcv9": ["CS_MODE_V9"],
|
||||
"sparcv9-unknown-linux": ["CS_MODE_V9"],
|
||||
"sparcel-linux-gnu": ["CS_MODE_LITTLE_ENDIAN"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"paths": {
|
||||
"{LLVM_ROOT}": "{AUTO_SYNC_ROOT}/vendor/llvm_root/",
|
||||
"{LLVM_TARGET_DIR}": "{LLVM_ROOT}/llvm/lib/Target/",
|
||||
"{LLVM_MC_TEST_DIR}": "{LLVM_ROOT}/llvm/test/MC/",
|
||||
"{LLVM_TBLGEN_BIN}": "{LLVM_ROOT}/build/bin/llvm-tblgen",
|
||||
"{LLVM_LIT_TEST_DIR}": "{AUTO_SYNC_SRC}/lit_config/",
|
||||
"{LLVM_INCLUDE_DIR}": "{LLVM_ROOT}/llvm/include/",
|
||||
"{VENDOR_DIR}": "{AUTO_SYNC_ROOT}/vendor/",
|
||||
"{BUILD_DIR}": "{AUTO_SYNC_ROOT}/build/",
|
||||
"{C_INC_OUT_DIR}": "{BUILD_DIR}/llvm_c_inc/",
|
||||
"{INC_GEN_CONF_FILE}": "{AUTO_SYNC_SRC}/inc_gen.json",
|
||||
"{CPP_INC_OUT_DIR}": "{BUILD_DIR}/llvm_cpp_inc/",
|
||||
"{CPP_TRANSLATOR_DIR}": "{AUTO_SYNC_SRC}/cpptranslator/",
|
||||
"{CPP_TRANSLATOR_CONFIG}": "{CPP_TRANSLATOR_DIR}/arch_config.json",
|
||||
"{CPP_TRANSLATOR_TEST_DIR}": "{CPP_TRANSLATOR_DIR}/Tests/",
|
||||
"{PATCHES_TEST_DIR}": "{CPP_TRANSLATOR_TEST_DIR}/Patches/",
|
||||
"{PATCHES_TEST_CONFIG}": "{PATCHES_TEST_DIR}/test_arch_config.json",
|
||||
"{DIFFER_PERSISTENCE_FILE}": "{CPP_TRANSLATOR_DIR}/saved_patches.json",
|
||||
"{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}": "{BUILD_DIR}/translate_out/",
|
||||
"{CPP_TRANSLATOR_DIFF_OUT_DIR}": "{BUILD_DIR}/diff_out/",
|
||||
"{INC_PATCH_DIR}": "{AUTO_SYNC_ROOT}/inc_patches/",
|
||||
"{CS_INCLUDE_DIR}": "{CS_ROOT}/include/capstone/",
|
||||
"{CS_ARCH_MODULE_DIR}": "{CS_ROOT}/arch/",
|
||||
"{CS_CLANG_FORMAT_FILE}": "{CS_ROOT}/.clang-format",
|
||||
"{HEADER_PATCHER_TEST_HEADER_FILE}": "{AUTO_SYNC_SRC}/Tests/test_header.h",
|
||||
"{HEADER_PATCHER_TEST_INC_FILE}": "{AUTO_SYNC_SRC}/Tests/test_include.inc",
|
||||
"{HEADER_GEN_TEST_AARCH64_FILE}": "{AUTO_SYNC_SRC}/Tests/test_aarch64_header.h",
|
||||
"{HEADER_GEN_TEST_ARM64_FILE}": "{AUTO_SYNC_SRC}/Tests/test_arm64_header.h",
|
||||
"{HEADER_GEN_TEST_ARM64_OUT_FILE}": "{AUTO_SYNC_SRC}/Tests/test_arm64_header.h.out",
|
||||
"{HEADER_GEN_TEST_SYSTEMZ_FILE}": "{AUTO_SYNC_SRC}/Tests/test_systemz_header.h",
|
||||
"{HEADER_GEN_TEST_SYSZ_FILE}": "{AUTO_SYNC_SRC}/Tests/test_sysz_header.h",
|
||||
"{HEADER_GEN_TEST_SYSZ_OUT_FILE}": "{AUTO_SYNC_SRC}/Tests/test_sysz_header.h.out",
|
||||
"{DIFFER_TEST_DIR}": "{CPP_TRANSLATOR_TEST_DIR}/Differ/",
|
||||
"{DIFFER_TEST_CONFIG_FILE}": "{DIFFER_TEST_DIR}/test_arch_config.json",
|
||||
"{DIFFER_TEST_OLD_SRC_DIR}": "{DIFFER_TEST_DIR}/old_src/",
|
||||
"{DIFFER_TEST_NEW_SRC_DIR}": "{DIFFER_TEST_DIR}/new_src/",
|
||||
"{DIFFER_TEST_OUTPUT_DIR}": "{DIFFER_TEST_DIR}/output/",
|
||||
"{DIFFER_TEST_EXPECTED_DIR}": "{DIFFER_TEST_DIR}/expected/",
|
||||
"{DIFFER_TEST_PERSISTENCE_FILE}": "{DIFFER_TEST_DIR}/test_saved_patches.json",
|
||||
"{AUTO_SYNC_TEST_DIR}": "{AUTO_SYNC_SRC}/Tests/",
|
||||
"{MCUPDATER_CONFIG_FILE}": "{AUTO_SYNC_SRC}/mcupdater.json",
|
||||
"{MCUPDATER_TEST_DIR}": "{AUTO_SYNC_TEST_DIR}/MCUpdaterTests/",
|
||||
"{MCUPDATER_TEST_DIR_EXPECTED}": "{AUTO_SYNC_TEST_DIR}/MCUpdaterTests/expected",
|
||||
"{MCUPDATER_OUT_DIR}": "{BUILD_DIR}/mc_out/",
|
||||
"{MCUPDATER_OUT_FUZZ_DIR}": "{BUILD_DIR}/mc_out_fuzz/",
|
||||
"{MCUPDATER_TEST_OUT_DIR}": "{MCUPDATER_TEST_DIR}/test_output/",
|
||||
"{MCUPDATER_TEST_OUT_FUZZ_DIR}": "{MCUPDATER_TEST_DIR}/test_output_fuzz/",
|
||||
"{MC_DIR}": "{CS_ROOT}/tests/MC/",
|
||||
"{LEGACY_MC_DIR}": "{CS_ROOT}/suite/MC/"
|
||||
},
|
||||
"create_during_runtime": [
|
||||
"{BUILD_DIR}",
|
||||
"{C_INC_OUT_DIR}",
|
||||
"{CPP_INC_OUT_DIR}",
|
||||
"{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}",
|
||||
"{CPP_TRANSLATOR_DIFF_OUT_DIR}",
|
||||
"{HEADER_GEN_TEST_ARM64_OUT_FILE}",
|
||||
"{HEADER_GEN_TEST_SYSZ_OUT_FILE}",
|
||||
"{MCUPDATER_OUT_DIR}",
|
||||
"{MCUPDATER_TEST_OUT_DIR}",
|
||||
"{MCUPDATER_OUT_FUZZ_DIR}",
|
||||
"{MCUPDATER_TEST_OUT_FUZZ_DIR}"
|
||||
],
|
||||
"ignore_missing": [
|
||||
"{DIFFER_TEST_PERSISTENCE_FILE}"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Directory for Capstone external auto-sync dependencies.
|
||||
|
||||
Reference in New Issue
Block a user