52 Commits
Author SHA1 Message Date
Anton Kochkov 8180b60b9a Merge 'dev' branch into stable 2026-06-21 10:14:03 +04:00
Anton Kochkov 1903c99b3a Merge branch 'stable' into stable-merge 2026-06-21 10:13:47 +04:00
wargio 65821969c1 Fix build on latest rizin dev 2026-06-02 15:08:39 +08:00
dependabot[bot] ac88882529 Bump github/codeql-action from 3 to 4 (#75)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-05 20:18:14 +08:00
dependabot[bot] 055f537948 Bump actions/checkout from 4 to 6 (#77)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-05 18:17:23 +08:00
dependabot[bot] 0d559b8bb6 Bump actions/setup-python from 5 to 6 (#74)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-05 17:18:29 +08:00
dependabot[bot] b63ab4b190 Bump actions/setup-node from 4 to 6 (#76)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-05 17:17:35 +08:00
dependabot[bot] 394628eaad Bump fsfe/reuse-action from 2 to 6 (#73)
Bumps [fsfe/reuse-action](https://github.com/fsfe/reuse-action) from 2 to 6.
- [Release notes](https://github.com/fsfe/reuse-action/releases)
- [Commits](https://github.com/fsfe/reuse-action/compare/v2...v6)

---
updated-dependencies:
- dependency-name: fsfe/reuse-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-05 17:16:31 +08:00
Khairul Azhar Kasmiran 02f34ad351 Enable dependabot pull requests (#72) 2026-04-05 16:52:52 +08:00
Khairul Azhar Kasmiran 9a567c14a6 ci: Replace windows-2019 with windows-2022 (#71) 2026-04-05 13:08:04 +08:00
Khairul Azhar Kasmiran c35c9a20f9 Fix build due to move to RzCoreDecodedBytes (#70) 2026-04-04 18:35:34 +08:00
Khairul Azhar Kasmiran 7676831b3b Rename master branch to stable (#69) 2026-02-22 14:38:40 +08:00
Khairul Azhar Kasmiran d958b56f64 Rename master branch to stable (#68) 2026-02-22 14:38:34 +08:00
Khairul Azhar Kasmiran f53ad7a2a1 Use C++20 for jsdec Cutter plugin 2026-02-17 19:10:35 +08:00
Giovanni 068f799e5e Fix core conf on cutter plugin (#64) 2025-04-25 13:23:56 +08:00
Giovanni 123fca01f8 Remove flag since is unsupported in macos and msvc 2025-03-06 20:22:54 +08:00
Giovanni 092ea99273 Fix cutter build by enforcing exclude-libs,ALL (#63) 2025-03-06 19:10:46 +08:00
Giovanni efeea7d750 Backport patches from r2dec and fix bug when calling pddi (#61) 2025-03-02 13:08:26 +08:00
Giovanni ccbbd071c4 Disable atomics when msvc does not support c11atomics (#60) 2024-10-21 16:40:52 +08:00
Giovanni 1576b650c1 Use QuickJS-NG 0.6.1 (#59) 2024-10-17 17:38:01 +08:00
wargio 3890f3f4c4 Fix reuse lint 2024-07-02 16:41:21 +08:00
wargio b16bff8263 Fix eslint ci job 2024-07-02 16:41:21 +08:00
wargio 9a721bfbdf Add UDF (UnDeFined) arm instruction 2024-07-02 16:41:21 +08:00
wargio b6f29a6a91 Fix arm data pointer when parsing. 2024-07-02 16:41:21 +08:00
Giovanni f07b5b8c06 Removed old tags (#56) 2024-03-19 20:22:33 +08:00
wargio c299b1823e Refactor how CI builds jsdec and rizin 2024-03-19 17:15:46 +08:00
wargio 58e1adf0ed For master always build against release, dev instead against dev. 2024-03-19 17:15:46 +08:00
wargio 21a9b20c09 Update bb to use pvec 2024-03-19 17:15:46 +08:00
Rot127 9bbd0fb2e3 Clone quickjs with depth = 1 to help people with bad connection. (#53) 2024-03-01 22:44:06 +08:00
Giovanni 906664e1fd Create cutter native plugin (#52) 2024-02-25 20:33:21 +08:00
Giovanni 0f966e3c2c Fix typo on INFINITY (#51) 2024-02-24 15:18:22 +08:00
Anton Kochkov ae4b7b8bac Fix for Rizin v0.7.0 (#49) 2024-02-24 13:28:24 +08:00
wargio 127c583d71 Fix usage of rz_core_analysis_bytes 2024-02-11 20:51:50 +08:00
wargio 5c8c212ef2 Format all yaml 2024-02-11 14:40:11 +08:00
wargio 9444500b7a Add CI flow for win64 plugin build 2024-02-11 14:40:11 +08:00
wargio c88c009777 Add CI flow for linux plugin build 2024-02-11 14:40:11 +08:00
wargio 667a05f328 Fix windows build due missing unix libs 2024-02-11 14:40:11 +08:00
wargio 925012f762 Add missing "b.le" on arm
* some disassemblers use use "b.le" instead of "ble"
2024-02-11 14:40:11 +08:00
bcc5f6bb2b Ignore the ARM64/PAC instructions
* Ignore the ARM64/PAC instructions as they add no value to the decompilation
* Handle PAC ret instructions as normal return instructions
* Implement `ldurh` instruction for arm64
* use functions instead of passing the original func.

---------

Co-authored-by: pancake <[email protected]>
Co-authored-by: Giovanni <[email protected]>
2024-02-11 14:40:11 +08:00
wargio 7b214758ce Always rebuild the bytecode. 2024-02-11 14:40:11 +08:00
wargio e0fe0489a2 Ignore null elements. 2024-02-11 14:40:11 +08:00
wargio 824106bd8a Fix movk 2024-02-11 14:40:11 +08:00
Jan Tojnar 2d5c43b75b README: Fix build instructions (#41)
The p/ directory no longer exists.
Also avoid calling meson without subcommand, which is ambiguous and deprecated.
2024-02-11 14:40:11 +08:00
Giovanni 67a069032f New db code does not have count element. (#40) 2024-02-11 14:40:11 +08:00
wargio 10dadc29ed Avoid to install headers. 2024-02-11 14:40:11 +08:00
wargio ed3bab7a26 Fix readme 2024-02-11 14:40:11 +08:00
wargio e70fabfd77 Update CI to use the correct paths 2024-02-11 14:40:11 +08:00
wargio 8a74f7b94c Support quickjs across all files. 2024-02-11 14:40:11 +08:00
wargio 3d115d9a9c moved javascript sources under js/ 2024-02-11 14:40:11 +08:00
wargio a87fa8cb0f Initial work with QuickJS from Frida 2024-02-11 14:40:11 +08:00
wargio 3eb1a5b27c Update engine name and added link 2023-08-18 12:54:28 +08:00
wargio ffecde4ae0 Implement missing sh op 2023-08-17 20:58:20 +08:00
155 changed files with 20785 additions and 127338 deletions

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
#!/bin/bash
set -e
CI_BRANCH="$1"
CI_JSDEC="$PWD"
CI_RZ_VERSION=$2
if [ "$CI_BRANCH" != "dev" ]; then
# stable branch always build against latest release of rizin
CI_RZ_VERSION=$(curl -s GET https://api.github.com/repos/rizinorg/rizin/tags\?per_page\=1 | jq -r '.[].name')
else
CI_RZ_VERSION="$CI_BRANCH"
fi
echo "CI_BRANCH: $CI_BRANCH"
echo "CI_RZ_VERSION: $CI_RZ_VERSION"
echo "CI_JSDEC: $CI_JSDEC"
# avoid placing rizin in the same folder.
cd ..
# download rizin
if [ "$CI_BRANCH" == "dev" ]; then
# dev branch always build against latest commit of rizin
wget -O "rizin.tar.gz" "https://github.com/rizinorg/rizin/archive/refs/heads/dev.tar.gz"
tar xf "rizin.tar.gz"
else
# stable branch always build against latest release of rizin
wget -O "rizin.tar.xz" "https://github.com/rizinorg/rizin/releases/download/$CI_RZ_VERSION/rizin-src-$CI_RZ_VERSION.tar.xz"
tar xf "rizin.tar.xz"
fi
# build rizin and install it.
cd "rizin-$CI_RZ_VERSION"
meson setup --buildtype=release -Denable_tests=false build
sudo ninja -C build install
# cleanup
cd ..
rm -rf "rizin-*"
# go back to the source folder of jsdec
cd "$CI_JSDEC"
# build jsdec and install in the rizin dir.
meson setup --buildtype=release -Dbuild_type=rizin --prefix=~/.local build
sudo ninja -C build install || sleep 0
# check if it was installed correctly and try to run it.
HAS_JSDEC=$(rizin -qc "Lc" | grep jsdec)
if [ -z "$HAS_JSDEC" ]; then
echo "rizin failed to load jsdec."
rizin -e log.level=0 -qc "Lc"
rizin -hh
exit 1
fi
OUTPUT=$(rizin -qc 'af ; pdd' /bin/ls)
CHECK=$(echo -e "$OUTPUT" | grep "jsdec pseudo code output")
echo -e "$OUTPUT"
if [ -z "$CHECK" ]; then
echo "rizin failed to exec jsdec."
exit 1
fi
+33
View File
@@ -0,0 +1,33 @@
.ci-scripts\vsdevenv.ps1 64
function Invoke-NativeCommand() {
if ($args.Count -eq 0) {
throw "Must supply some arguments."
}
$command = $args[0]
$commandArgs = @()
if ($args.Count -gt 1) {
$commandArgs = $args[1..($args.Count - 1)]
}
& $command $commandArgs
$result = $LASTEXITCODE
if ($result -ne 0) {
throw "$command $commandArgs exited with code $result."
}
}
$rizin_path = "C:$env:HOMEPATH\AppData\Local\Programs\rizin"
$env:PATH = "$env:PATH;C:$env:HOMEPATH\AppData\Local\Programs\rizin\bin"
$env:PKG_CONFIG_PATH = "C:$env:HOMEPATH\AppData\Local\Programs\rizin\lib\pkgconfig"
$env:CFLAGS = "-IC:$env:HOMEPATH\AppData\Local\Programs\rizin\include\librz -IC:$env:HOMEPATH\AppData\Local\Programs\rizin\include\librz\sdb"
$env:LDFLAGS = "-LC:$env:HOMEPATH\AppData\Local\Programs\rizin\lib"
Invoke-NativeCommand meson setup --buildtype=release --prefix="$rizin_path" build
Invoke-NativeCommand ninja -C build install
rizin.exe -e log.level=2 -qc "Lc"
rizin.exe -qc "af ; pdd" "C:\Windows\System32\calc.exe"
+2 -2
View File
@@ -2,7 +2,7 @@
set -e
## NPM eslint
npm install -s eslint
npm install --save-dev eslint
## NPM test
find ./libdec -type f -name "*.js" | xargs node_modules/.bin/eslint -c ./.eslintrc.json
find ./js -type f -name "*.js" | xargs node_modules/.bin/eslint --stats -c ./.eslint.config.js
+24
View File
@@ -0,0 +1,24 @@
import urllib.request
import json
import sys
import os
out_file = "rizin.zip"
latest = "stable" if len(sys.argv) < 1 else sys.argv[1]
if latest != "dev":
# stable branch always build against latest release of rizin
tags = None
with urllib.request.urlopen('https://api.github.com/repos/rizinorg/rizin/tags?per_page=1') as f:
tags = json.load(f)
latest = tags[0]['name']
url = f"https://github.com/rizinorg/rizin/archive/refs/tags/{latest}.zip"
else:
# dev branch always build against latest commit of rizin
url = "https://github.com/rizinorg/rizin/archive/refs/heads/dev.zip"
print(f"Using rizin branch: {latest}")
print(f"{url} as {out_file}")
urllib.request.urlretrieve(url, out_file)
+10 -17
View File
@@ -1,24 +1,17 @@
#!/bin/bash
set -e
sudo apt update > /dev/null
sudo apt -y install meson ninja-build
CI_BRANCH="$1"
CI_JSDEC="$PWD"
echo "Branch: $CI_BRANCH"
make --no-print-directory testbin -C p
ERRORED=$?
if [ "$ERRORED" == "1" ]; then
exit $ERRORED
fi
echo "CI_BRANCH: $CI_BRANCH"
echo "CI_JSDEC: $CI_JSDEC"
## jsdec-test
cd ..
CI_WORKDIR=$(pwd)
echo "Work dir: $CI_WORKDIR"
rm -rf jsdec-test >/dev/null 2>&1 || echo "no need to clean.."
git clone --branch "$CI_BRANCH" --depth 1 https://github.com/rizinorg/jsdec-test || git clone --depth 1 https://github.com/rizinorg/jsdec-test
cd jsdec-test
rm -rf tests >/dev/null 2>&1 || echo "no need to clean.."
git clone --branch "$CI_BRANCH" --depth 1 https://github.com/rizinorg/jsdec-test tests || git clone --depth 1 https://github.com/rizinorg/jsdec-test tests
cd tests
chmod +x testall.sh
./testall.sh "$CI_WORKDIR/jsdec" travis
ERRORED=$?
cd ..
./testall.sh "$CI_JSDEC" travis
+8 -5
View File
@@ -1,7 +1,10 @@
$bits = $args[0]
$installationPath = vswhere.exe -latest -property installationPath
if ($installationPath -and (test-path "$installationPath\Common7\Tools\vsdevcmd.bat")) {
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -no_logo && set" | foreach-object {
$name, $value = $_ -split '=', 2
set-content env:\"$name" $value
if (-not $installationPath -or -not (test-path "$installationPath\VC\Auxiliary\Build\vcvars$bits.bat")) {
throw "vcvars$bits.bat file not found"
}
& "${env:COMSPEC}" /s /c "`"$installationPath\VC\Auxiliary\Build\vcvars$bits.bat`" > nul 2>&1 && set" | . { process {
if ($_ -match '^([^=]+)=(.*)') {
[System.Environment]::SetEnvironmentVariable($matches[1], $matches[2])
}
}
}}
View File
File renamed without changes.
+21 -22
View File
@@ -1,10 +1,22 @@
{
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "script",
"ecmaFeatures": {}
module.exports = {
"languageOptions": {
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"ecmaFeatures": {}
},
"globals": {
"process": true,
"BigInt": true,
"Global": true,
"Limits": true,
"rizin": true,
"atob": true,
"btoa": true,
"unit": true,
"console": true
}
},
"extends": "eslint:recommended",
"rules": {
"semi": [2, "always"],
"no-console": ["error", {
@@ -18,6 +30,7 @@
}],
"no-unused-vars": ["error", {
"varsIgnorePattern": "jsdec_|\\binclude\\b",
"caughtErrors": "none",
"args": "none"
}],
"curly": "error",
@@ -26,20 +39,6 @@
"no-constant-condition": ["error", {
"checkLoops": false
}],
"no-control-regex": "warn"
},
"globals": {
"Global": true,
"Duktape": true,
"TextDecoder": true,
"require": true,
"include": true,
"read_file": true,
"module": true,
"console": true,
"rzcmd": true,
"rz_func_graph": true,
"___internal_load": true,
"___internal_require": true
"no-control-regex": "warn"
}
}
};
+7
View File
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: "weekly"
+66
View File
@@ -0,0 +1,66 @@
name: build-plugin
on:
push:
branches:
- stable
- dev
pull_request:
# Automatically cancel any previous workflow on new push.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
linux:
runs-on: ubuntu-latest
steps:
- name: Checkout commit
uses: actions/checkout@v6
- name: Install dependencies
run: sudo apt -y install meson ninja-build
- name: Build & run jsdec as rizin plugin
run: bash .ci-scripts/ci-build-linux.sh "${{ github.event.pull_request.base.ref || github.ref_name }}"
windows-latest:
runs-on: ${{ matrix.os }}
name: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- "windows-latest"
- "windows-2022"
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.9.x
- name: Preparing msvc toolchain
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Install dependencies
shell: bash
run: |
pip install ninja meson PyYAML
choco install pkgconfiglite
choco install zip
- name: Fetch & build rizin
shell: bash
run: |
WORKDIR="$PWD"
cd ..
python "$WORKDIR/.ci-scripts/ci-rizin-dl.py" '${{ github.event.pull_request.base.ref || github.ref_name }}'
unzip -q rizin.zip
rm *.zip
mv rizin* rizin-build
cd rizin-build
powershell.exe ".\dist\windows\build_windows_installer.ps1 vs2019_static 64 --default-library=shared -Dportable=true"
ls ./dist/windows/Output
powershell.exe '.\dist\windows\Output\rizin.exe /SP- /SILENT /CURRENTUSER'
cd "$WORKDIR"
- name: Build & run jsdec as rizin plugin
shell: pwsh
run: .ci-scripts\ci-build-win.ps1 64
+7 -7
View File
@@ -2,9 +2,9 @@ name: "CodeQL"
on:
push:
branches: [ "master" ]
branches: ["stable", "dev"]
pull_request:
branches: [ "master" ]
branches: ["stable", "dev"]
schedule:
- cron: "1 14 * * 5"
@@ -20,22 +20,22 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ javascript ]
language: [javascript]
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v6
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v4
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{ matrix.language }}"
+15 -15
View File
@@ -2,7 +2,8 @@ name: continuous-tests
on:
push:
branches:
- master
- stable
- dev
pull_request:
jobs:
@@ -10,28 +11,27 @@ jobs:
name: eslint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '16'
node-version: "21"
- name: eslint
run: chmod +x .ci-scripts/ci-eslint.sh && .ci-scripts/ci-eslint.sh ${GITHUB_REF##*/}
run: chmod +x .ci-scripts/ci-eslint.sh && .ci-scripts/ci-eslint.sh
tests:
name: tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Checkout jsdec-test
uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: tests
run: chmod +x .ci-scripts/ci-tests.sh && .ci-scripts/ci-tests.sh ${GITHUB_REF##*/}
run: chmod +x .ci-scripts/ci-tests.sh && .ci-scripts/ci-tests.sh "${{ github.ref_name }}"
licenses:
name: licenses
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: REUSE Compliance Check
uses: fsfe/reuse-action@v1.1
- name: Checkout repository
uses: actions/checkout@v6
- name: Reuse Compliance Check
uses: fsfe/reuse-action@v6
with:
args: --suppress-deprecation lint
+5 -12
View File
@@ -1,12 +1,5 @@
/nbproject/
/node_modules/
p/build
p/clean
p/core_pdd.so
p/jsdec-test
/themes/*.json
core_pdd.so
p/*.o
p/duktape/*.o
.DS_Store
.cache/
build*/
subprojects/libquick*/
node_modules/
package.json
package-lock.json
+12 -13
View File
@@ -15,7 +15,7 @@ Files: .github/**/*
Copyright: 2018-2021 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
Files: .eslintrc.json
Files: .eslint.config.js
Copyright: 2018-2021 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
@@ -31,23 +31,22 @@ Files: eslint-check.sh
Copyright: 2018-2019 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
Files: p/duktape/*
Copyright: 2013-2019 Duktape
License: MIT
Files: subprojects/*
Copyright: 2023 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
Files: p/meson.build
Files: subprojects/**/*
Copyright: 2023 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
Files: meson_options.txt
Copyright: 2021 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
Files: p/meson_options.txt
Files: .clang-format
Copyright: 2021 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
Files: p/.clang-format
Copyright: 2021 Giovanni Dante Grazioli <[email protected]>
Files: cutter-plugin/CMakeLists.txt
Copyright: 2024 Giovanni Dante Grazioli <[email protected]>
License: BSD-3-Clause
Files: p/Makefile
Copyright: 2017-2021 Giovanni Dante Grazioli <[email protected]>
Copyright: 2017-2018 pancake <[email protected]>
License: BSD-3-Clause
+47 -48
View File
@@ -1,54 +1,50 @@
# Developing on jsdec
jsdec is mostly written in javascript and the engine is duktape.
Duktape APIs: https://duktape.org/api.html
`jsdec` is written in javascript uses [QuickJS](https://bellard.org/quickjs/).
## Extending jsdec arch
First of all when you need to add a new architecture, you need to create a new `.js` file inside `libdec/arch/`.
First of all when you need to add a new architecture, you need to create a new `.js` file inside `js/libdec/arch/`.
For example `libdec/arch/arch9999.js` and it needs to follow the minimal base javascript template:
For example `js/libdec/arch/arch9999.js` and it needs to follow the minimal base javascript template:
```js
(function() { // lgtm [js/useless-expression]
const Base = require('libdec/core/base');
const Variable = require('libdec/core/variable');
const Extra = require('libdec/core/extra');
return {
instructions: {
add: function(instr, context, instructions) {
return Base.add(instr.parsed.opd[0], instr.parsed.opd[1], instr.parsed.opd[2]);
},
nop: function() {
return Base.nop();
},
invalid: function(instr, context, instructions) {
return Base.nop();
}
import Base from '../core/base.js';
import Variable from '../core/variable.js';
import Extra from '../core/extra.js';
return {
instructions: {
add: function(instr, context, instructions) {
return Base.add(instr.parsed.opd[0], instr.parsed.opd[1], instr.parsed.opd[2]);
},
parse: function(assembly) {
var tokens = assembly.trim().split(' ');
return { mnem: tokens.shift(), opd: tokens };
nop: function() {
return Base.nop();
},
context: function() {
return { cond: { a: '?', b: '?' } };
},
preanalisys: function(instructions, context) {},
postanalisys: function(instructions, context) {},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
invalid: function(instr, context, instructions) {
return Base.nop();
}
};
});
},
parse: function(assembly) {
var tokens = assembly.trim().split(' ');
return { mnem: tokens.shift(), opd: tokens };
},
context: function() {
return { cond: { a: '?', b: '?' } };
},
preanalisys: function(instructions, context) {},
postanalisys: function(instructions, context) {},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
```
After saving the new arch (`arch9999.js` in the example), you need to add this arch to the file `libdec/Archs.js`.
@@ -56,13 +52,16 @@ The new architecture needs to have the same name as the cmd `e asm.arch`, becaus
For example:
```js
(function() {
return {
arm: require('libdec/arch/arm'),
arch9999: require('libdec/arch/arch9999'),
x86: require('libdec/arch/x86')
};
});
import arm from './arch/arm.js';
import x86 from './arch/x86.js';
import arch9999 from './arch/arch9999.js';
export default {
arm: arm,
arch9999: arch9999,
x86: x86
};
```
## Codebase:
-73
View File
@@ -1,73 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+23 -119
View File
@@ -1,9 +1,6 @@
![Build Status](https://github.com/rizinorg/jsdec/workflows/continuous-tests/badge.svg)
[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/rizinorg/jsdec.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/rizinorg/jsdec/context:javascript)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/rizinorg/jsdec.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/rizinorg/jsdec/alerts/)
[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
![jsdec](https://raw.githubusercontent.com/rizinorg/jsdec/master/.github/logo.png)
![jsdec](https://raw.githubusercontent.com/rizinorg/jsdec/dev/.github/logo.png)
Converts asm to pseudo-C code.
@@ -11,23 +8,20 @@ Converts asm to pseudo-C code.
Requires [rizin](https://github.com/rizinorg/rizin).
# Install system wide
Follow the following steps to install jsdec
- clone this repository
- Run `cd p`
- Run `meson -Djsc_folder=".." --prefix=/usr build` to create the build folder
- Run `ninja -C build install` to build the shared library and to install it
# Install in home folder (or in other paths)
If you want to install in the HOME folder or in other non standard paths, just
set the `prefix` to a different value
- Run `cd p`
- Run ``meson -Djsc_folder=".." --prefix=~/.local build``
- Run ``meson setup build --prefix=~/.local``
- Run `ninja -C build install`
# Install system wide
Follow the following steps to install jsdec
- clone this repository
- Run `meson setup build --prefix=/usr` to create the build folder
- Run `ninja -C build install` to build the shared library and to install it
# Usage
* Open your file with rizin
@@ -37,34 +31,18 @@ set the `prefix` to a different value
# Arguments
```
[0x00000000]> pdd?Usage: pdd [args] - core plugin for jsdec
pdd - decompile current function
pdd? - show this help
pdd* - the decompiled code is returned to rizin as comment (via CCu)
pdda - decompile current function side by side with assembly
pddb - decompile current function but shows only scopes
pddo - decompile current function side by side with offsets
pddi - generates the issue data
Environment
JSDEC_HOME defaults to the root directory of the jsdec repo
[0x00000000]> pdd --help
jsdec [options]
--help | this help message
--assembly | shows pseudo next to the assembly
--blocks | shows only scopes blocks
--casts | shows all casts in the pseudo code
--colors | enables syntax colors
--debug | do not catch exceptions
--html | outputs html data instead of text
--issue | generates the json used for the test suite
--offsets | shows pseudo next to the assembly offset
--paddr | all xrefs uses physical addresses instead of virtual addresses
--xrefs | shows also instruction xrefs in the pseudo code
--as-comment | the decompiled code is returned to rizin as comment (via CCu)
--as-opcode | the decompiled code is returned to rizin as opcode (via aho)
[0x00000000]> pdd?
Usage: pdd[?] # Core plugin for jsdec
| pdd # decompile current function
| pddt # lists the supported architectures
| pdda # decompile current function with side assembly
| pddA # decompile current function with annotation output
| pddb # decompile current function but show only scopes
| pddc # decompiled code is returned to rizin as 'file:line code' (via CL)
| pddf # decompile all functions
| pddi # generate issue data
| pddj # decompile current function as json
| pddo # decompile current function side by side with offsets
```
# Evaluable vars
@@ -102,86 +80,12 @@ e scr.color | enables syntax colors.
PowerPC 32/64 bit (VLE included)
RISC-V
Sparc
superh (experimental)
SuperH (experimental)
v850
WebAssembly (experimental)
x86/x64
# Developing on jsdec
[Read DEVELOPERS.md](https://github.com/rizinorg/jsdec/blob/master/DEVELOPERS.md)
[Read DEVELOPERS.md](https://github.com/rizinorg/jsdec/blob/dev/DEVELOPERS.md)
## Example
This example shows a possible dump of the plugin.
### Source Code
```c
#include <stdio.h>
int main(int argc, char const *argv[]) {
int var = 0;
while(var < 0x90) {
if(var < 0x10) {
var += 0x50;
}
var += 0x10;
}
return 0;
}
```
### rizin view
```
╭ (fcn) main 50
│ main (int arg1, int arg2);
│ ; var int local_20h @ rbp-0x20
│ ; var int local_14h @ rbp-0x14
│ ; var signed int local_4h @ rbp-0x4
│ ; DATA XREF from entry0 (0x1041)
│ 0x00001119 55 push rbp
│ 0x0000111a 4889e5 mov rbp, rsp
│ 0x0000111d 897dec mov dword [local_14h], edi ; arg1
│ 0x00001120 488975e0 mov qword [local_20h], rsi ; arg2
│ 0x00001124 c745fc000000. mov dword [local_4h], 0
│ ╭─< 0x0000112b eb0e jmp 0x113b
│ │ ; CODE XREF from main (0x1142)
│ ╭──> 0x0000112d 837dfc0f cmp dword [local_4h], 0xf ; [0xf:4]=0x3e000300
│ ╭───< 0x00001131 7f04 jg 0x1137
│ │⋮│ 0x00001133 8345fc50 add dword [local_4h], 0x50 ; 'P'
│ │⋮│ ; CODE XREF from main (0x1131)
│ ╰───> 0x00001137 8345fc10 add dword [local_4h], 0x10
│ ⋮│ ; CODE XREF from main (0x112b)
│ ⋮╰─> 0x0000113b 817dfc8f0000. cmp dword [local_4h], 0x8f ; [0x8f:4]=0x2a800
│ ╰──< 0x00001142 7ee9 jle 0x112d
│ 0x00001144 b800000000 mov eax, 0
│ 0x00001149 5d pop rbp
╰ 0x0000114a c3 ret
```
### jsdec pseudo-C code
```c
/* jsdec pseudo C output */
#include <stdint.h>
int32_t main (int32_t argc, char ** argv) {
char ** local_20h;
int32_t local_14h;
int32_t local_4h;
local_14h = edi;
local_20h = rsi;
local_4h = 0;
while (local_4h <= 0x8f) {
if (local_4h <= 0xf) {
local_4h += 0x50;
}
local_4h += 0x10;
}
eax = 0;
return eax;
}
```
+403
View File
@@ -0,0 +1,403 @@
// SPDX-FileCopyrightText: 2013 William Sherif
// SPDX-License-Identifier: MIT
#include "base64.h"
// MAPS
// b64 maps 0=>A, 1=>B..63=>/ etc
// ----------1---------2---------3---------4---------5---------6---
// 0123456789012345678901234567890123456789012345678901234567890123
const static char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// unb64 maps A=>0, B=>1.. and all others not present in base64 alphabet to 0.
// You can clearly see here why base64 encoding is a really bloated representation
// of the original data: look how many entries are unused. Each ascii character
// can index any value between 0-255 in an array, but we're only using 64 of
// the available slots for meaningful values, leaving 192/256 values unused.
// clang-format off
const static unsigned char unb64[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50
54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60
0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90
25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120
49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250
0, 0, 0, 0, 0, 0,
}; // This array has 256 elements
// clang-format on
// Converts any binary data to base64 characters.
// Length of the resultant string is stored in flen
// (you must pass pointer flen). flen is strlen, it doesn't
// include the null terminator.
// A common trip-up is not passing your null terminator into
// this function, if you want your C string to be fully encoded,
// you have to pass strlen(str)+1 to as binaryData as I have in the
// examples.
char *base64(const void *binaryData, int len, int *flen) {
printf("Base64 encoding %d bytes of binary data\n", len);
// I look at your data like the stream of unsigned bytes that it is
const unsigned char *bin = (const unsigned char *)binaryData;
int lenMod3 = len % 3;
// PAD. Base64 is all about breaking the input into SEXTETS, or 6-bit inputs.
// If you have 1 byte of input, that's 8 bits, not 6. So it won't fit.
// We need the input to be a multiple of 6. So 8 bits would be padded
// by 2 bytes to make the total input size 24 bits, which is divisible by 6.
// A 2 byte input is 16 bits, which is not divisible by 6. So we pad it
// by 1 byte to make it 24 bits, which is now divisible by 6.
// We use modulus 3 bytes above because that's 24 bits, and 24 bits is
// the lowest number that is both divisible by 6 and 8. We need the final
// output data is to both be divisible by 6 and 8.
int pad = ((lenMod3 & 1) << 1) + ((lenMod3 & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0.
*flen = 4 * (len + pad) / 3; // (len+pad) IS divisible by 3
// So, final length IS a multiple of 4 for a valid base64 string.
printf("%d %% 3 = %d, %d bytes pad, +1 byte NULL, flen=%d\n", len, lenMod3, pad, *flen);
// Allocate enough space for the base64 string result.
char *base64String = (char *)malloc(*flen + 1); // and one for the null,
// which is NOT counted in flen.
if (!base64String) {
puts("ERROR: base64 could not allocate enough memory.");
puts("I must stop because I could not get enough");
return 0;
}
// EXTRACTING SEXTETS FROM THE OCTETS.
// byte0 byte1 byte2
// +-----------+-----------+-----------+
// | 0000 0011 0111 1011 1010 1101 |
// +-AAAA AABB BBBB CCCC CCDD DDDD
//
// In 3 bytes (really, 3 "octets") there are __4__ sextets.
// You can see that from the diagram above. byte0 (0000 0011) contains
// the first sextet (AAAA AA) and 2 bits of the 2nd sextet (BB).
// byte1 contains the next 4 bits of the 2nd sextet (BBBB) and 4 bits
// of the 3rd sextet (CCCC). byte2 has 2 bits of the 3rd sextet and
// all 6 bits of the 4th sextet.
//
// You can see why we process in groups of 3 bytes: because 3*8 = 24
// and 24 is the lowest common multiple between 6 and 8. To divide
// a group of bytes EVENLY into groups of 6, the number of bytes has to
// be a multiple of 3.
// Talking in bits, the input already HAS to be a multiple of 8 (because you just
// can't have anything smaller than a byte saved to memory or disk on modern
// computers). To successfully convert the bitstream into groups of 6 bits, we'll force
// the input bitstream to being a MULTIPLE OF 24, so that it will evenly
// divide by 6.
// For that reason, we have the concept of PADDING: if the original octet
// stream is NOT a multiple of 3, then we pad it with 1 or 2 extra bytes
// so that it is a multiple of 3.
// So without further ado let's extract the 4 sextets from the 3 octets!
// Convert sextets in stream into the base64 alphabet using b64 array
// the value in 6 bits can never be larger than 63, but the b64 array
// protects us from OOB accesses anyway by providing
// We want to shift the first 6 bits in the above diagram down to sitting
// flushed to the right. So we want bin[0] (containing AAAA AABB) to just
// become 00AA AAAA. We do that with a shift right of 2 bits.
// We take the number that comes out of that and immediately convert it to
// the base64 character for that number by doing a direct lookup into the
// b64 encoding array.
// We devise 4 formulae below, SEXTET1, SEXTET2, SEXTET3 and SEXTET4. They
// are used to extract the 4 sextets from the 3 octets that we have.
#define SEXTET_A(byte0) (byte0 >> 2)
// Note that no mask needed since BYTE0 is unsigned, so 0's always come in from left
// (even though there is implicit int promotion on R&L sides prior to actual bitshift).
// the second sextet BBBBBB is part of the first byte and partly in the 2nd byte.
// BYTE0 BYTE1
// AAAA AABB BBBB CCCC
// The first part takes the lower 2 bits of the first byte and pushes them
// LEFT 4: (AAAA AABB becomes 00BB 0000), then bitwise ORs to it the top 4 bits of
// BYTE1, shifted RIGHT 4 (BBBB CCCC becomes 0000 BBBB).
#define SEXTET_B(byte0, byte1) (((0x3 & byte0) << 4) | (byte1 >> 4))
// 3rd sextet CCCCCC is lower nibble of 2nd byte and upper half nibble of 3rd byte.
// BYTE1 BYTE2
// BBBB CCCC CCDD DDDD
// From BYTE1, we need to get rid of the BBBB in the front, so we mask
// those off with 0xf (0000 1111). Then we shift BYTE1 LEFT 2
// (BBBB CCCC becomes 00CC CC00).
// We need to fill in the bottom 2 bits of 00CC CC00 with the top 2 bits
// in BYTE2. So we just shift BYTE2 right by 6 bits (CCDD DDDD becomes 0000 00CC).
#define SEXTET_C(byte1, byte2) (((0xf & byte1) << 2) | (byte2 >> 6))
// 4th sextet
// already low order, just mask off 2 hiorder bits
// BYTE2
// CCDD DDDD
// We just want to mask off the top 2 bits, use mask 0011 1111 or just 0x3f
#define SEXTET_D(byte2) (0x3f & byte2)
int i = 0, byteNo; // result counter, and which byte we're on of the original source data.
// I still need these variables after the loop
for (byteNo = 0; byteNo <= len - 3; // This loop is NOT entered for if there
// are trailing bytes that are not a multiple of 3 bytes,
// since we skip in 3's.
// If there WAS padding, skip the last 3 octets and process below.
// 0=>no, 1=>no, 2=>no, 3=>ONCE,4=>ONCE,5=>ONCE, 6=>2x..
byteNo += 3) // jump in 3's
{
// Use unsigned char so shifts left will always bring in 0's
unsigned char BYTE0 = bin[byteNo];
unsigned char BYTE1 = bin[byteNo + 1];
unsigned char BYTE2 = bin[byteNo + 2];
// printf( "BYTE0=%d BYTE1=%d BYTE2=%d\n", BYTE0, BYTE1, BYTE2 ) ;
// To form the base64String, we make lookups with the base64 numeric
// values into the base64 "alphabet" that is present in the b64 array.
base64String[i++] = b64[SEXTET_A(BYTE0)];
base64String[i++] = b64[SEXTET_B(BYTE0, BYTE1)];
base64String[i++] = b64[SEXTET_C(BYTE1, BYTE2)];
base64String[i++] = b64[SEXTET_D(BYTE2)];
}
// The last 3 octets must be converted carefully as if len%3==1 or len%3==2 we must
// "pretend" there are additional bits at the end.
if (pad == 1) {
unsigned char BYTE0 = bin[byteNo];
unsigned char BYTE1 = bin[byteNo + 1];
// printf( "BYTE0=%d BYTE1=%d\n", BYTE0, BYTE1 ) ;
// When len%3==2 (2,5,8,11) (missing 1 byte).
// - 3 sextets (C is 0 padded)
// bin[0] bin[1] bin[2]
// +-----------+-----------+-----------+
// | 0000 0011 1111 1111 ~~~~ ~~~~ |
// +-AAAA AABB BBBB CCCC XXXX XXXX
// Here all the ~ are actually going to be considered __0__'s.
base64String[i++] = b64[SEXTET_A(BYTE0)];
base64String[i++] = b64[SEXTET_B(BYTE0, BYTE1)];
// We can't use the SEXTET3 formula because we only have 2 bytes to work
// with. The 3rd byte (BYTE2) is actually 0 here. You could call
// SEXTET3(BYTE1, 0), but to save some ops we just write what will actually
// be needed here only.
base64String[i++] = b64[(0xf & BYTE1) << 2];
// Last one is = to indicate there has been a padding of 1 byte.
base64String[i++] = '=';
} else if (pad == 2) // len%3==1 (1,4,7,10)
{
unsigned char BYTE0 = bin[byteNo];
// printf( "BYTE0=%d\n", BYTE0 ) ;
// We are missing 2 bytes. So
// - we will only extract 2 sextets when len%3==1
// - The 2nd sextet's 2 HI ORDER BITS, NOT LO-ORDER.
// - are being specified by the lowest 2 bits of the 1st octet. these should be 0.
// bin[0] bin[1] bin[2]
// +-----------+-----------+-----------+
// | 0000 0011 ~~~~ ~~~~ ~~~~ ~~~~ |
// +-AAAA AABB XXXX XXXX XXXX XXXX
base64String[i++] = b64[SEXTET_A(BYTE0)];
base64String[i++] = b64[(0x3 & BYTE0) << 4]; // "padded" by 0's, these 2 bits are still HI ORDER BITS.
// Last 2 are ==, to indicate there's been a 2 byte-pad
base64String[i++] = '=';
base64String[i++] = '=';
}
base64String[i] = 0; // NULL TERMINATOR! ;)
return base64String;
}
unsigned char *unbase64(const char *ascii, int len, int *flen) {
#ifdef SAFEBASE64
if (!base64integrity(ascii, len))
return 0; // NULL PTR if bad integrity.
#endif
const unsigned char *safeAsciiPtr = (const unsigned char *)ascii; // internally I use
// an unsigned char pointer, so that __the maximum value read out is 255,
// and the value is never negative__. This is a type of
// "if statement" enforced by the type of the pointer.
// This eliminates a possible bounds check on your array lookups into unb64[]
// (*(unsigned char*) having values between 0 and 255 means it will always be
// inside the bounds of the 256 element array).
int pad = 0;
if (len > 1) {
// Count == on the end to determine how much it was padded.
if (safeAsciiPtr[len - 1] == '=')
++pad;
if (safeAsciiPtr[len - 2] == '=')
++pad;
}
// You take the ascii string len and divide it by 4
// to get the number of 3 octet groups. You then *3 to
// get #octets total.
// If len<4, we makes sure you get a flen of 0, because that's not even
// a valid base64 string at all.
*flen = 3 * (len / 4) - pad;
if (*flen < 0)
*flen = 0;
unsigned char *bin = (unsigned char *)malloc(*flen);
if (!bin) {
puts("ERROR: unbase64 could not allocate enough memory.");
puts("I must stop because I could not get enough");
return 0;
}
int cb = 0; // counter for bin
int charNo; // counter for what base64 char we're currently decoding
// NEVER do the last group of 4 characters if either of the
// last 2 chars were pad.
for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) {
// Get the numbers each character represents
// Since ascii is ONE BYTE, the worst that can happen is
// you get a bunch of 0's back (if the base64 string contained
// characters not in the base64 alphabet).
// The only way unbase64 will TELL you about this though
// is if you #define SAFEBASE64 (particularly because
// there is a 3-4x performance hit, just for the integrity check.)
int A = unb64[safeAsciiPtr[charNo]];
// printf( "[%4d] %c => %d\n", charNo, ascii[charNo], A ) ;
int B = unb64[safeAsciiPtr[charNo + 1]];
// printf( "[%4d] %c => %d\n", charNo+1, ascii[charNo+1], B ) ;
int C = unb64[safeAsciiPtr[charNo + 2]];
// printf( "[%4d] %c => %d\n", charNo+2, ascii[charNo+2], C ) ;
int D = unb64[safeAsciiPtr[charNo + 3]];
// printf( "[%4d] %c => %d\n", charNo+3, ascii[charNo+3], D ) ;
// Just unmap each sextet to THE NUMBER it represents.
// You then have to pack it in bin,
// we go in groups of 4 sextets,
// and pull out 3 octets per quad of sextets.
// bin[0] bin[1] bin[2]
// +-----------+-----------+-----------+
// | 0000 0011 0111 1011 1010 1101 |
// +-AAAA AABB BBBB CCCC CCDD DDDD
// or them
bin[cb++] = (A << 2) | (B >> 4); // OR in last 2 bits of B
// The 2nd byte is the bottom 4 bits of B for the upper nibble,
// and the top 4 bits of C for the lower nibble.
bin[cb++] = (B << 4) | (C >> 2);
bin[cb++] = (C << 6) | (D); // shove C up to top 2 bits, or with D
}
// If the length of the string were not a multiple of 4, then the string
// was damaged and some data was lost.
if (isMultipleOf(len, 4)) {
if (pad == 1) {
// 1 padding character.
// bin[0] bin[1] bin[2]
// +-----------+-----------+-----------+
// | 0000 0011 1111 1111 ~~~~ ~~~~ |
// +-AAAA AABB BBBB CCCC XXXX XXXX
// We can pull 2 bytes out, not 3.
// We have __3__ characters A,B and C, not 4.
int A = unb64[safeAsciiPtr[charNo]];
int B = unb64[safeAsciiPtr[charNo + 1]];
int C = unb64[safeAsciiPtr[charNo + 2]];
bin[cb++] = (A << 2) | (B >> 4);
bin[cb++] = (B << 4) | (C >> 2);
} else if (pad == 2) {
// bin[0] bin[1] bin[2]
// +-----------+-----------+-----------+
// | 0000 0011 ~~~~ ~~~~ ~~~~ ~~~~ |
// +-AAAA AABB XXXX XXXX XXXX XXXX
int A = unb64[safeAsciiPtr[charNo]];
int B = unb64[safeAsciiPtr[charNo + 1]];
bin[cb++] = (A << 2) | (B >> 4);
}
}
return bin;
}
// There are some invalid unbase64 strings, even when they are comprised
// of completely valid characters. An example is "==". That's a 0-length
// piece of data that says it is padded by 2 bytes at the end. Well, you
// only need to pad by 2 bytes if the number of bits in the original data
// was not evenly divisible by 6. 0%6==0, so something's clearly wrong here.
int base64integrity(const char *ascii, int len) {
// The base64 string is somewhat inflated, since each ASCII character
// represents only a 6-bit value (a sextet). That leaves 2 bits wasted per 8 bits used.
// More importantly, for the sextet stream you're getting here (inside
// an octet stream) to be VALID, THE LENGTH HAS TO BE A MULTIPLE OF 4.
// You can see in the base64 function above, the algorithm always writes
// into the final base64 string in groups of __4__.
// So from there, you can see a valid base64 string has just gotta have a
// length that is a multiple of 4.
// If it does not, then it simply isn't valid base64 and the string should
// be rejected. There really is little sense in trying to decode invalid
// base64, because it's probably some kind of attack.
// If the length is not a multiple of 4, it's invalid base64.
// Here, the empty string will be valid base64 because it represents empty data.
if (len % 4)
return 0;
// LOOKING FOR BAD CHARACTERS
int i;
for (i = 0; i < len - 2; i++) {
if (!isbase64ValidChr(ascii[i])) {
printf("ERROR in base64integrity at chr %d [%c]. String is NOT valid base64.\n", i, ascii[i]);
return 0;
}
}
// Only last 2 can be '='
// Check 2nd last:
if (ascii[i] == '=') {
// If the 2nd last is = the last MUST be = too
if (ascii[i + 1] != '=') {
printf("ERROR in base64integrity at chr %d.\n"
"If the 2nd last chr is '=' then the last chr must be '=' too.\n "
"String is NOT valid base64.",
i);
return 0;
}
} else if (!isbase64ValidChr(ascii[i])) // not = or valid base64
{
// 2nd last was invalid and not '='
printf("ERROR in base64integrity at chr %d (2nd last chr). String is NOT valid base64.\n", i);
return 0;
}
// check last
i++;
if (ascii[i] != '=' && !isbase64ValidChr(ascii[i])) {
printf("ERROR in base64integrity at chr %d (last chr). String is NOT valid base64.\n", i);
return 0;
}
// Otherwise if get here, b64 string was valid.
return 1;
}
+44
View File
@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: 2013 William Sherif
// SPDX-License-Identifier: MIT
#ifndef BASE64_H
#define BASE64_H
#include <stdio.h>
#include <stdlib.h>
// The COMPILE-TIME SETTING SAFEBASE64 is really important.
// You need to decide if PARANOIA is more important to you than speed.
//
// SAFEBASE64: Remove this def to NOT check the validity of base64 ascii strings
// before unbase64'ing that string. If you don't #define SAFEBASE64,
// then the program assumes that all characters in the string sent to unbase64()
// are in the base64 alphabet. As such if a character is NOT in the base64 alphabet
// your data will be wrong (it will be turned to 0 (as if it were just a base64 'A')).
// Removing this test greatly speeds up unbase64'ing (by about 3-4x).
#define SAFEBASE64
#define isMultipleOf(a, x) (!((a) % x))
// Converts any binary data to base64 characters.
// Length of the resultant string is stored in flen
// (you must pass pointer flen).
char *base64(const void *binaryData, int len, int *flen);
// Convert your base64 string haJIh/+ back to binary data.
// len is the string length and should NOT include the null terminator.
// Final size will be stored in flen
// (you must pass pointer flen).
unsigned char *unbase64(const char *ascii, int len, int *flen);
// Checks the integrity of a base64 string to make sure it is
// made up of only characters in the base64 alphabet (array b64)
#define isbase64ValidChr(ch) (('0' <= ch && ch <= '9') || \
('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || \
ch == '+' || ch == '/') // other 2 valid chars, + ending chrs
// = is NOT considered a valid base64 chr, it's only valid at the end for padding
// Tells you if a string is valid base64, which means it's length is
// a multiple of 4, and it contains only valid base64 chrs.
int base64integrity(const char *ascii, int len);
#endif
+375
View File
@@ -0,0 +1,375 @@
// SPDX-FileCopyrightText: 2024 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#include <stdlib.h>
#include <string.h>
#include <rz_types.h>
#include <rz_lib.h>
#include <rz_cmd.h>
#include <rz_core.h>
#include <rz_cons.h>
#include <rz_analysis.h>
#include "jsdec.h"
#include "jsdec-cutter.h"
typedef struct rz_core_t RzCore;
typedef struct exec_context_t {
RzCore *core;
void *bed;
RzStrBuf *anno;
JSValue shared;
} ExecContext;
static JSValue js_analysis_bytes(JSContext *ctx, RzCore *core, RzCoreDecodedBytes *cdb) {
RzAnalysisOp *aop = &cdb->an_op;
JSValue op = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, op, "offset", JS_NewBigUint64(ctx, aop->addr));
if (aop->ptr != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "ptr", JS_NewBigUint64(ctx, aop->ptr));
}
if (aop->val != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "val", JS_NewBigUint64(ctx, aop->val));
}
JS_SetPropertyStr(ctx, op, "opcode", JS_NewString(ctx, rz_str_get_null(cdb->opcode)));
JS_SetPropertyStr(ctx, op, "disasm", JS_NewString(ctx, rz_str_get_null(cdb->disasm)));
JS_SetPropertyStr(ctx, op, "type", JS_NewString(ctx, rz_analysis_optype_to_string(aop->type)));
if (aop->jump != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "jump", JS_NewBigInt64(ctx, aop->jump));
}
if (aop->fail != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "fail", JS_NewBigUint64(ctx, aop->fail));
}
const char *comment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, aop->addr);
if (RZ_STR_ISNOTEMPTY(comment)) {
JS_SetPropertyStr(ctx, op, "comment", JS_NewString(ctx, comment));
}
return op;
}
static JSValue js_analysis_opcodes(JSContext *ctx, RzCore *core) {
RzCoreDecodedBytes *cdb;
JSValue ops = JS_NewArray(ctx);
st64 op_idx = 0;
RzIterator *iter = rz_core_analysis_bytes(core, core->offset, core->block, core->blocksize, 0);
if (!iter) {
return ops;
}
rz_iterator_foreach(iter, cdb) {
if (!cdb || !strcmp(cdb->opcode, "nop")) {
continue;
}
JSValue op = js_analysis_bytes(ctx, core, cdb);
JS_SetPropertyInt64(ctx, ops, op_idx, op);
op_idx++;
}
rz_iterator_free(iter);
return ops;
}
static JSValue js_function_bbs(JSContext *ctx, RzCore *core, RzAnalysisFunction *fcn) {
JSValue bbs = JS_NewArray(ctx);
RzAnalysisBlock *bbi;
void **iter;
st64 bbs_idx = 0;
ut64 old_offset = core->offset;
ut64 old_bsize = core->blocksize;
rz_pvector_foreach (fcn->bbs, iter) {
bbi = (RzAnalysisBlock *)*iter;
rz_core_block_size(core, bbi->size);
rz_core_seek(core, bbi->addr, true);
JSValue bb = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, bb, "address", JS_NewBigUint64(ctx, bbi->addr));
if (bbi->jump != UT64_MAX) {
JS_SetPropertyStr(ctx, bb, "jump", JS_NewBigUint64(ctx, bbi->jump));
}
if (bbi->fail != UT64_MAX) {
JS_SetPropertyStr(ctx, bb, "fail", JS_NewBigUint64(ctx, bbi->fail));
}
JSValue ops = js_analysis_opcodes(ctx, core);
JS_SetPropertyStr(ctx, bb, "ops", ops);
JS_SetPropertyInt64(ctx, bbs, bbs_idx, bb);
bbs_idx++;
}
rz_core_block_size(core, old_bsize);
rz_core_seek(core, old_offset, true);
return bbs;
}
static JSValue js_command(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
if (argc != 1) {
return JS_EXCEPTION;
}
const char *command = JS_ToCString(ctx, argv[0]);
if (!command) {
return JS_EXCEPTION;
}
ExecContext *ectx = (ExecContext *)JS_GetContextOpaque(ctx);
RzCore *core = ectx->core;
rz_cons_sleep_end(ectx->bed);
char *output = rz_core_cmd_str(core, command);
JS_FreeCString(ctx, command);
JSValue result = JS_NewString(ctx, output ? output : "");
free(output);
ectx->bed = rz_cons_sleep_begin();
return result;
}
static JSValue js_graph(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
if (argc != 0) {
return JS_EXCEPTION;
}
ExecContext *ectx = (ExecContext *)JS_GetContextOpaque(ctx);
RzCore *core = ectx->core;
rz_cons_sleep_end(ectx->bed);
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, -1);
if (!fcn) {
ectx->bed = rz_cons_sleep_begin();
return JS_ThrowInternalError(ctx, "Cannot find function at 0x%08" PFMT64x, core->offset);
}
JSValue graph = JS_NewArray(ctx);
JSValue object = JS_NewObject(ctx);
JS_SetPropertyInt64(ctx, graph, 0, object);
JS_SetPropertyStr(ctx, object, "name", JS_NewString(ctx, rz_str_get_null(fcn->name)));
JSValue blocks = js_function_bbs(ctx, core, fcn);
JS_SetPropertyStr(ctx, object, "blocks", blocks);
ectx->bed = rz_cons_sleep_begin();
return graph;
}
static JSValue js_console_log(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
ExecContext *ectx = (ExecContext *)JS_GetContextOpaque(ctx);
for (int i = 0; i < argc; ++i) {
if (i != 0) {
rz_strbuf_append_n(ectx->anno, " ", 1);
}
const char *str = JS_ToCString(ctx, argv[i]);
if (!str) {
return JS_EXCEPTION;
}
rz_strbuf_append(ectx->anno, str);
JS_FreeCString(ctx, str);
}
rz_strbuf_append_n(ectx->anno, "\n", 1);
return JS_UNDEFINED;
}
static JSValue js_get_global(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
ExecContext *ectx = (ExecContext *)JS_GetContextOpaque(ctx);
return JS_GetPropertyStr(ctx, ectx->shared, "Shared");
}
static jsdec_t *jsdec_create(ExecContext *ec) {
jsdec_t *dec = jsdec_new();
if (!dec) {
return NULL;
}
JSContext *ctx = jsdec_context(dec);
JS_SetContextOpaque(ctx, ec);
ec->shared = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, ec->shared, "Shared", JS_NewObject(ctx));
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global, "Global", JS_NewCFunction(ctx, js_get_global, "Global", 1));
JSValue console = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "console", console);
JS_SetPropertyStr(ctx, console, "log", JS_NewCFunction(ctx, js_console_log, "log", 1));
JSValue rizin = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "rizin", rizin);
JS_SetPropertyStr(ctx, rizin, "command", JS_NewCFunction(ctx, js_command, "command", 1));
JS_SetPropertyStr(ctx, rizin, "graph", JS_NewCFunction(ctx, js_graph, "graph", 1));
JSValue process = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "process", process);
JSValue args = JS_NewArray(ctx);
JS_SetPropertyInt64(ctx, args, 0, JS_NewString(ctx, "--annotation"));
JS_SetPropertyStr(ctx, process, "args", args);
JS_FreeValue(ctx, global);
return dec;
}
static void jsdec_destroy(jsdec_t *dec, ExecContext *ec) {
JSContext *ctx = jsdec_context(dec);
JS_FreeValue(ctx, ec->shared);
jsdec_free(dec);
}
static char *json_to_strdup(const RzJson *object, const char *key) {
const RzJson *j = rz_json_get(object, key);
if (!j || j->type != RZ_JSON_STRING) {
return NULL;
}
return rz_str_dup(j->str_value);
}
static const char *json_as_string(const RzJson *object, const char *key) {
const RzJson *j = rz_json_get(object, key);
if (!j || j->type != RZ_JSON_STRING) {
return NULL;
}
return j->str_value;
}
static ut64 json_as_ut64(const RzJson *object, const char *key) {
const RzJson *j = rz_json_get(object, key);
if (!j || (j->type != RZ_JSON_STRING && j->type != RZ_JSON_INTEGER)) {
return 0;
}
if (j->type == RZ_JSON_INTEGER) {
return j->num.u_value;
} else if (rz_num_is_valid_input(NULL, j->str_value)) {
return rz_num_get_input_value(NULL, j->str_value);
}
return 0;
}
static RzAnnotatedCode *parse_json(RzStrBuf *sb) {
char *text = rz_strbuf_drain(sb);
if (RZ_STR_ISEMPTY(text)) {
free(text);
return NULL;
}
// text is modified by rz_json_parse and
// is freed by rz_json_free
RzJson *json = rz_json_parse(text);
if (!json) {
RZ_LOG_ERROR("failed to parse from json string\n");
return NULL;
}
char *raw_code = json_to_strdup(json, "code");
if (!raw_code) {
rz_json_free(json);
RZ_LOG_ERROR("failed to dup code\n");
return NULL;
}
RzAnnotatedCode *code = rz_annotated_code_new(raw_code);
if (!code) {
rz_json_free(json);
RZ_LOG_ERROR("failed to create RzAnnotatedCode\n");
return NULL;
}
const RzJson *annotations = rz_json_get(json, "annotations");
const RzJson *element = NULL;
for (size_t idx = 0; annotations && (element = rz_json_item(annotations, idx)); idx++) {
RzCodeAnnotation annotation = { 0 };
annotation.start = json_as_ut64(element, "start");
annotation.end = json_as_ut64(element, "end");
const char *type = json_as_string(element, "type");
if (!strcmp(type, "offset")) {
annotation.type = RZ_CODE_ANNOTATION_TYPE_OFFSET;
annotation.offset.offset = json_as_ut64(element, "offset");
} else if (!strcmp(type, "function_name")) {
annotation.type = RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME;
annotation.reference.name = json_to_strdup(element, "name");
annotation.reference.offset = json_as_ut64(element, "offset");
} else if (!strcmp(type, "global_variable")) {
annotation.type = RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE;
annotation.reference.offset = json_as_ut64(element, "offset");
} else if (!strcmp(type, "constant_variable")) {
annotation.type = RZ_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE;
annotation.reference.offset = json_as_ut64(element, "offset");
} else if (!strcmp(type, "local_variable")) {
annotation.type = RZ_CODE_ANNOTATION_TYPE_LOCAL_VARIABLE;
annotation.variable.name = json_to_strdup(element, "name");
} else if (!strcmp(type, "function_parameter")) {
annotation.type = RZ_CODE_ANNOTATION_TYPE_FUNCTION_PARAMETER;
annotation.variable.name = json_to_strdup(element, "name");
} else if (!strcmp(type, "syntax_highlight")) {
annotation.type = RZ_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT;
const char *highlightType = json_as_string(element, "syntax_highlight");
if (!strcmp(highlightType, "keyword")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_KEYWORD;
} else if (!strcmp(highlightType, "comment")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_COMMENT;
} else if (!strcmp(highlightType, "datatype")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_DATATYPE;
} else if (!strcmp(highlightType, "function_name")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME;
} else if (!strcmp(highlightType, "function_parameter")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER;
} else if (!strcmp(highlightType, "local_variable")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE;
} else if (!strcmp(highlightType, "constant_variable")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE;
} else if (!strcmp(highlightType, "global_variable")) {
annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE;
}
}
rz_annotated_code_add_annotation(code, &annotation);
}
rz_json_free(json);
return code;
}
RZ_API void jsdec_init_config(RzCore *core) {
RzConfig *cfg = core->config;
rz_config_lock(cfg, false);
SETPREF("jsdec.asm", "false", "if true, shows pseudo next to the assembly.");
SETPREF("jsdec.blocks", "false", "if true, shows only scopes blocks.");
SETPREF("jsdec.casts", "false", "if false, hides all casts in the pseudo code.");
SETPREF("jsdec.debug", "false", "do not catch exceptions in jsdec.");
SETPREF("jsdec.highlight", "default", "highlights the current address.");
SETPREF("jsdec.paddr", "false", "if true, all xrefs uses physical addresses compare.");
SETPREF("jsdec.slow", "false", "load all the data before to avoid multirequests to rizin.");
SETPREF("jsdec.xrefs", "false", "if true, shows all xrefs in the pseudo code.");
rz_config_lock(cfg, true);
}
RZ_API RzAnnotatedCode *jsdec_as_annotation(RzCore *core, ut64 addr) {
ExecContext ectx;
ectx.core = core;
ectx.anno = rz_strbuf_new("");
if (!ectx.anno) {
rz_strbuf_free(ectx.anno);
RZ_LOG_ERROR("failed to create RzStrBuf\n");
return NULL;
}
jsdec_t *dec = jsdec_create(&ectx);
if (!dec) {
rz_strbuf_free(ectx.anno);
RZ_LOG_ERROR("failed to create jsdec_t\n");
return NULL;
}
ut64 offset = core->offset;
if (offset != addr) {
rz_core_seek(core, addr, true);
}
ectx.bed = rz_cons_sleep_begin();
bool ret = jsdec_run(dec);
rz_cons_sleep_end(ectx.bed);
if (offset != addr) {
rz_core_seek(core, offset, true);
}
jsdec_destroy(dec, &ectx);
if (!ret) {
rz_strbuf_free(ectx.anno);
RZ_LOG_ERROR("jsdec_run returned false\n");
return NULL;
}
return parse_json(ectx.anno);
}
+351
View File
@@ -0,0 +1,351 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#include <stdlib.h>
#include <string.h>
#include <rz_types.h>
#include <rz_lib.h>
#include <rz_cmd.h>
#include <rz_core.h>
#include <rz_cons.h>
#include <rz_analysis.h>
#include "jsdec.h"
typedef struct rz_core_t RzCore;
typedef struct exec_context_t {
RzCore *core;
void *bed;
JSValue shared;
} ExecContext;
#undef RZ_API
#define RZ_API static
#undef RZ_IPI
#define RZ_IPI static
#define SETDESC(x, y) rz_config_node_desc(x, y)
#define SETPREF(x, y, z) SETDESC(rz_config_set(cfg, x, y), z)
#define name_args(name) (internal_##name##_args)
#define name_help(name) (internal_##name##_help)
#define name_handler(name) (internal_##name##_handler)
#define command_handler(name, arg) \
RZ_IPI RzCmdStatus name_handler(name)(RzCore * core, int argc, const char **argv) { \
if (argc != 1) { \
return RZ_CMD_STATUS_WRONG_ARGS; \
} \
jsdec_main(core, arg); \
return RZ_CMD_STATUS_OK; \
}
#define static_description_no_args(command, description) \
static const RzCmdDescArg name_args(command)[] = { \
{ 0 }, \
}; \
static const RzCmdDescHelp name_help(command) = { \
.summary = description, \
.args = name_args(command), \
}
#define rz_cmd_desc_argv_new_warn(rcmd, root, cmd) \
rz_warn_if_fail(rz_cmd_desc_argv_new(rcmd, root, #cmd, name_handler(cmd), &name_help(cmd)))
static JSValue js_analysis_bytes(JSContext *ctx, RzCore *core, RzCoreDecodedBytes *cdb) {
RzAnalysisOp *aop = &cdb->an_op;
JSValue op = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, op, "offset", JS_NewBigUint64(ctx, aop->addr));
if (aop->ptr != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "ptr", JS_NewBigUint64(ctx, aop->ptr));
}
if (aop->val != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "val", JS_NewBigUint64(ctx, aop->val));
}
JS_SetPropertyStr(ctx, op, "opcode", JS_NewString(ctx, rz_str_get_null(cdb->opcode)));
JS_SetPropertyStr(ctx, op, "disasm", JS_NewString(ctx, rz_str_get_null(cdb->disasm)));
JS_SetPropertyStr(ctx, op, "type", JS_NewString(ctx, rz_analysis_optype_to_string(aop->type)));
if (aop->jump != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "jump", JS_NewBigInt64(ctx, aop->jump));
}
if (aop->fail != UT64_MAX) {
JS_SetPropertyStr(ctx, op, "fail", JS_NewBigUint64(ctx, aop->fail));
}
const char *comment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, aop->addr);
if (RZ_STR_ISNOTEMPTY(comment)) {
JS_SetPropertyStr(ctx, op, "comment", JS_NewString(ctx, comment));
}
return op;
}
static JSValue js_analysis_opcodes(JSContext *ctx, RzCore *core) {
RzCoreDecodedBytes *cdb;
JSValue ops = JS_NewArray(ctx);
st64 op_idx = 0;
RzIterator *iter = rz_core_analysis_bytes(core, core->offset, core->block, core->blocksize, 0);
if (!iter) {
return ops;
}
rz_iterator_foreach (iter, cdb) {
if (!cdb || !strcmp(cdb->opcode, "nop")) {
continue;
}
JSValue op = js_analysis_bytes(ctx, core, cdb);
JS_SetPropertyInt64(ctx, ops, op_idx, op);
op_idx++;
}
rz_iterator_free(iter);
return ops;
}
static JSValue js_function_bbs(JSContext *ctx, RzCore *core, RzAnalysisFunction *fcn) {
JSValue bbs = JS_NewArray(ctx);
RzAnalysisBlock *bbi;
void **iter;
st64 bbs_idx = 0;
ut64 old_offset = core->offset;
ut64 old_bsize = core->blocksize;
rz_pvector_foreach (fcn->bbs, iter) {
bbi = (RzAnalysisBlock *)*iter;
rz_core_block_size(core, bbi->size);
rz_core_seek(core, bbi->addr, true);
JSValue bb = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, bb, "address", JS_NewBigUint64(ctx, bbi->addr));
if (bbi->jump != UT64_MAX) {
JS_SetPropertyStr(ctx, bb, "jump", JS_NewBigUint64(ctx, bbi->jump));
}
if (bbi->fail != UT64_MAX) {
JS_SetPropertyStr(ctx, bb, "fail", JS_NewBigUint64(ctx, bbi->fail));
}
JSValue ops = js_analysis_opcodes(ctx, core);
JS_SetPropertyStr(ctx, bb, "ops", ops);
JS_SetPropertyInt64(ctx, bbs, bbs_idx, bb);
bbs_idx++;
}
rz_core_block_size(core, old_bsize);
rz_core_seek(core, old_offset, true);
return bbs;
}
static JSValue js_command(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
if (argc != 1) {
return JS_EXCEPTION;
}
const char *command = JS_ToCString(ctx, argv[0]);
if (!command) {
return JS_EXCEPTION;
}
ExecContext *ectx = (ExecContext *)JS_GetContextOpaque(ctx);
RzCore *core = ectx->core;
rz_cons_sleep_end(ectx->bed);
char *output = rz_core_cmd_str(core, command);
JS_FreeCString(ctx, command);
JSValue result = JS_NewString(ctx, output ? output : "");
free(output);
ectx->bed = rz_cons_sleep_begin();
return result;
}
static JSValue js_graph(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
if (argc != 0) {
return JS_EXCEPTION;
}
ExecContext *ectx = (ExecContext *)JS_GetContextOpaque(ctx);
RzCore *core = ectx->core;
rz_cons_sleep_end(ectx->bed);
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, core->offset, -1);
if (!fcn) {
ectx->bed = rz_cons_sleep_begin();
return JS_ThrowInternalError(ctx, "Cannot find function at 0x%08" PFMT64x, core->offset);
}
JSValue graph = JS_NewArray(ctx);
JSValue object = JS_NewObject(ctx);
JS_SetPropertyInt64(ctx, graph, 0, object);
JS_SetPropertyStr(ctx, object, "name", JS_NewString(ctx, rz_str_get_null(fcn->name)));
JSValue blocks = js_function_bbs(ctx, core, fcn);
JS_SetPropertyStr(ctx, object, "blocks", blocks);
ectx->bed = rz_cons_sleep_begin();
return graph;
}
static JSValue js_console_log(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
for (int i = 0; i < argc; ++i) {
if (i != 0) {
rz_cons_print(" ");
}
const char *str = JS_ToCString(ctx, argv[i]);
if (!str) {
return JS_EXCEPTION;
}
rz_cons_print(str);
JS_FreeCString(ctx, str);
}
rz_cons_newline();
rz_cons_flush();
return JS_UNDEFINED;
}
static JSValue js_get_global(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
ExecContext *ectx = (ExecContext *)JS_GetContextOpaque(ctx);
return JS_GetPropertyStr(ctx, ectx->shared, "Shared");
}
static jsdec_t *jsdec_create(ExecContext *ec, const char *arg) {
jsdec_t *dec = jsdec_new();
if (!dec) {
return NULL;
}
JSContext *ctx = jsdec_context(dec);
JS_SetContextOpaque(ctx, ec);
ec->shared = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, ec->shared, "Shared", JS_NewObject(ctx));
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global, "Global", JS_NewCFunction(ctx, js_get_global, "Global", 1));
JSValue console = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "console", console);
JS_SetPropertyStr(ctx, console, "log", JS_NewCFunction(ctx, js_console_log, "log", 1));
JSValue rizin = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "rizin", rizin);
JS_SetPropertyStr(ctx, rizin, "command", JS_NewCFunction(ctx, js_command, "command", 1));
JS_SetPropertyStr(ctx, rizin, "graph", JS_NewCFunction(ctx, js_graph, "graph", 1));
JSValue process = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "process", process);
JSValue args = JS_NewArray(ctx);
if (RZ_STR_ISNOTEMPTY(arg)) {
JS_SetPropertyInt64(ctx, args, 0, JS_NewString(ctx, arg));
}
JS_SetPropertyStr(ctx, process, "args", args);
JS_FreeValue(ctx, global);
return dec;
}
static void jsdec_destroy(jsdec_t *dec, ExecContext *ec) {
JSContext *ctx = jsdec_context(dec);
JS_FreeValue(ctx, ec->shared);
jsdec_free(dec);
}
static bool jsdec_main(RzCore *core, const char *arg) {
ExecContext ectx;
ectx.core = core;
jsdec_t *dec = jsdec_create(&ectx, arg);
if (!dec) {
return false;
}
ectx.bed = rz_cons_sleep_begin();
bool ret = jsdec_run(dec);
rz_cons_sleep_end(ectx.bed);
jsdec_destroy(dec, &ectx);
return ret;
}
static const RzCmdDescHelp pdd_usage = {
.summary = "Core plugin for jsdec",
};
// static_description_no_args(cmd_pdd_star,"decompiled code is returned to rizin as comment (via CCu)");
static_description_no_args(pdd, "decompile current function");
static_description_no_args(pddt, "lists the supported architectures");
static_description_no_args(pddc, "decompiled code is returned to rizin as 'file:line code' (via CL)");
static_description_no_args(pdda, "decompile current function with side assembly");
static_description_no_args(pddb, "decompile current function but show only scopes");
static_description_no_args(pddo, "decompile current function side by side with offsets");
static_description_no_args(pddj, "decompile current function as json");
static_description_no_args(pddA, "decompile current function with annotation output");
static_description_no_args(pddf, "decompile all functions");
static_description_no_args(pddi, "generate issue data");
command_handler(pdd, NULL);
command_handler(pddt, "--architectures");
command_handler(pdda, "--assembly");
command_handler(pddA, "--annotation");
command_handler(pddb, "--blocks");
command_handler(pddc, "--as-code-line");
command_handler(pddf, "--all-functions");
command_handler(pddi, "--issue");
command_handler(pddj, "--as-json");
command_handler(pddo, "--offsets");
static bool rz_cmd_pdd_init(RzCore *core, void **user) {
(void)user;
RzCmd *rcmd = core->rcmd;
RzConfig *cfg = core->config;
RzCmdDesc *root_cd = rz_cmd_get_desc(rcmd, "pd");
if (!root_cd) {
rz_warn_if_reached();
return false;
}
rz_config_lock(cfg, false);
SETPREF("jsdec.asm", "false", "if true, shows pseudo next to the assembly.");
SETPREF("jsdec.blocks", "false", "if true, shows only scopes blocks.");
SETPREF("jsdec.casts", "false", "if false, hides all casts in the pseudo code.");
SETPREF("jsdec.debug", "false", "do not catch exceptions in jsdec.");
SETPREF("jsdec.highlight", "default", "highlights the current address.");
SETPREF("jsdec.paddr", "false", "if true, all xrefs uses physical addresses compare.");
SETPREF("jsdec.slow", "false", "load all the data before to avoid multirequests to rizin.");
SETPREF("jsdec.xrefs", "false", "if true, shows all xrefs in the pseudo code.");
rz_config_lock(cfg, true);
RzCmdDesc *pdd = rz_cmd_desc_group_new(rcmd, root_cd, "pdd", name_handler(pdd), &name_help(pdd), &pdd_usage);
if (!pdd) {
rz_warn_if_reached();
return false;
}
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddt);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pdda);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddA);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddb);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddc);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddf);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddi);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddj);
rz_cmd_desc_argv_new_warn(rcmd, pdd, pddo);
return true;
}
static bool rz_cmd_pdd_fini(RzCore *core, void *user) {
(void)user;
RzCmd *rcmd = core->rcmd;
RzCmdDesc *cd = rz_cmd_get_desc(rcmd, "pdd");
return rz_cmd_desc_remove(rcmd, cd);
}
RzCorePlugin rz_core_plugin_jsdec = {
.name = "jsdec",
.author = "deroad",
.desc = "Pseudo-code decompiler for rizin",
.license = "BSD-3-Clause",
.init = rz_cmd_pdd_init,
.fini = rz_cmd_pdd_fini,
};
#ifdef _MSC_VER
#define _RZ_API __declspec(dllexport)
#else
#define _RZ_API __attribute__((visibility("default")))
#endif
#ifndef CORELIB
_RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_CORE,
.data = &rz_core_plugin_jsdec,
.version = RZ_VERSION,
};
#endif
+145
View File
@@ -0,0 +1,145 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "jsdec.h"
#define errorf(...) fprintf(stderr, __VA_ARGS__)
static JSValue shared;
int is_regular_file(const char *path) {
if (!path || !*path) {
return 0;
}
struct stat path_stat;
stat(path, &path_stat);
return S_ISREG(path_stat.st_mode);
}
static char *read_file(const char *filename) {
FILE *fp = NULL;
long size = 0;
char *buffer = NULL;
if (!is_regular_file(filename)) {
errorf("Error: path '%s' is not a file\n", filename);
return NULL;
}
fp = fopen(filename, "rb");
if (!fp) {
errorf("Error: failed opening file '%s'\n", filename);
return NULL;
}
fseek(fp, 0, SEEK_END); // non-portable
size = ftell(fp);
rewind(fp);
if (size < 1) {
errorf("Error: negative size (%ld) of '%s'\n", size, filename);
goto fail;
}
if (!(buffer = malloc(size + 1))) {
errorf("Error: ENOMEM (%ld bytes) of '%s'\n", size, filename);
goto fail;
}
int read_bytes = fread(buffer, 1, size, fp);
if (read_bytes != size) {
errorf("Error: failed to read (%d/%ld bytes) from '%s'\n", read_bytes, size, filename);
goto fail;
}
// + 1 as on malloc
buffer[size] = 0;
fclose(fp);
return buffer;
fail:
fclose(fp);
free(buffer);
return NULL;
}
static JSValue js_console_log(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
for (int i = 0; i < argc; ++i) {
if (i != 0) {
fputc(' ', stdout);
}
const char *str = JS_ToCString(ctx, argv[i]);
if (!str) {
return JS_EXCEPTION;
}
fputs(str, stdout);
JS_FreeCString(ctx, str);
}
fputc('\n', stdout);
fflush(stdout);
return JS_UNDEFINED;
}
static JSValue js_get_global(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
return JS_GetPropertyStr(ctx, shared, "Shared");
}
static int init_testsuite(jsdec_t *dec, const char *file, const char *raw) {
JSContext *ctx = jsdec_context(dec);
shared = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, shared, "Shared", JS_NewObject(ctx));
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global, "Global", JS_NewCFunction(ctx, js_get_global, "Global", 1));
JS_SetPropertyStr(ctx, global, "rizin", JS_NULL);
JSValue console = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "console", console);
JS_SetPropertyStr(ctx, console, "log", JS_NewCFunction(ctx, js_console_log, "log", 1));
JSValue unit = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "unit", unit);
JS_SetPropertyStr(ctx, unit, "file", JS_NewString(ctx, file));
JS_SetPropertyStr(ctx, unit, "raw", JS_NewString(ctx, raw));
JS_FreeValue(ctx, global);
return 1;
}
static void fini_testsuite(jsdec_t *dec) {
JSContext *ctx = jsdec_context(dec);
JS_FreeValue(ctx, shared);
jsdec_free(dec);
}
int main(int argc, char const *argv[]) {
if (argc != 2 || !strcmp(argv[1], "-h")) {
errorf("usage: %s <issue.json>\n", argv[0]);
return 1;
}
jsdec_t *dec = NULL;
char *raw = read_file(argv[1]);
if (!raw) {
return 1;
}
if (!(dec = jsdec_new())) {
free(raw);
return 1;
}
init_testsuite(dec, argv[1], raw);
free(raw);
int ret = !jsdec_run(dec);
fini_testsuite(dec);
return ret;
}
+247
View File
@@ -0,0 +1,247 @@
// SPDX-FileCopyrightText: 2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "base64.h"
#include "jsdec.h"
#include "js/bytecode.h"
struct jsdec_s {
JSRuntime *runtime;
JSContext *context;
};
#define macro_str(s) #s
#define errorf(...) fprintf(stderr, __VA_ARGS__)
void js_print_exception(JSContext *ctx, JSValueConst val) {
const char *strval = JS_ToCString(ctx, val);
if (strval) {
fprintf(stderr, "%s\n", strval);
JS_FreeCString(ctx, strval);
} else {
fprintf(stderr, "[exception]\n");
}
}
void jsdec_handle_exception(JSContext *ctx) {
JSValue exception = JS_GetException(ctx);
int is_error = JS_IsError(ctx, exception);
js_print_exception(ctx, exception);
if (!is_error) {
JS_FreeValue(ctx, exception);
return;
}
JSValue stack = JS_GetPropertyStr(ctx, exception, "stack");
if (!JS_IsUndefined(stack)) {
js_print_exception(ctx, stack);
}
JS_FreeValue(ctx, stack);
JS_FreeValue(ctx, exception);
}
#if 0
static void print_jsval(JSValue val) {
if(JS_IsNumber(val)) {
errorf("JS_IsNumber\n");
} else if(JS_IsBigInt(NULL, val)) {
errorf("JS_IsBigInt\n");
} else if(JS_IsBool(val)) {
errorf("JS_IsBool\n");
} else if(JS_IsNull(val)) {
errorf("JS_IsNull\n");
} else if(JS_IsUndefined(val)) {
errorf("JS_IsUndefined\n");
} else if(JS_IsException(val)) {
errorf("JS_IsException\n");
} else if(JS_IsUninitialized(val)) {
errorf("JS_IsUninitialized\n");
} else if(JS_IsString(val)) {
errorf("JS_IsString\n");
} else if(JS_IsSymbol(val)) {
errorf("JS_IsSymbol\n");
} else if(JS_IsObject(val)) {
errorf("JS_IsObject\n");
} else if(JS_VALUE_GET_TAG(val) == JS_TAG_MODULE) {
errorf("Module\n");
} else if(JS_VALUE_GET_TAG(val) == JS_TAG_FUNCTION_BYTECODE) {
errorf("Function bytecode\n");
} else {
errorf("No idea...\n");
}
}
#endif
static int js_add_module(JSContext *ctx, const uint8_t *bytecode, const uint32_t size) {
JSValue obj = JS_ReadObject(ctx, bytecode, size, JS_READ_OBJ_BYTECODE);
if (JS_IsException(obj)) {
jsdec_handle_exception(ctx);
return 0;
}
return 1;
}
static int js_load_module(JSContext *ctx, const uint8_t *bytes, const uint32_t size) {
JSValue obj = JS_ReadObject(ctx, bytes, size, JS_READ_OBJ_BYTECODE);
if (JS_IsException(obj)) {
jsdec_handle_exception(ctx);
return 0;
}
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE &&
JS_ResolveModule(ctx, obj) < 0) {
JS_FreeValue(ctx, obj);
errorf("Error: failed to resolve jsdec module\n");
return 0;
}
//print_jsval(obj);
JSValue val = JS_EvalFunction(ctx, obj);
if (JS_IsException(val)) {
errorf("Error: jsdec thrown an exception when loading a module\n");
jsdec_handle_exception(ctx);
return 0;
}
JS_FreeValue(ctx, val);
return 1;
}
#include "js/bytecode_mod.h"
void jsdec_free(jsdec_t *dec) {
if (!dec) {
return;
}
JS_FreeContext(dec->context);
JS_FreeRuntime(dec->runtime);
free(dec);
}
static JSValue js_atob(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
if (argc != 1 || !JS_IsString(argv[0])) {
return JS_EXCEPTION;
}
const char *encoded = JS_ToCString(ctx, argv[0]);
if (!encoded) {
return JS_EXCEPTION;
}
int length = (int)strlen(encoded);
if (length < 1 || !base64integrity(encoded, length)) {
JS_FreeCString(ctx, encoded);
return JS_ThrowInternalError(ctx, "Invalid base64 string");
}
int flen = 0;
char *decoded = (char *)unbase64(encoded, length, &flen);
JS_FreeCString(ctx, encoded);
JSValue result = JS_NewStringLen(ctx, decoded, flen);
free(decoded);
return result;
}
static JSValue js_btoa(JSContext *ctx, JSValueConst jsThis, int argc, JSValueConst *argv) {
if (argc != 1 || !JS_IsString(argv[0])) {
return JS_EXCEPTION;
}
const char *decoded = JS_ToCString(ctx, argv[0]);
if (!decoded) {
return JS_EXCEPTION;
}
int length = (int)strlen(decoded);
if (length < 0) {
JS_FreeCString(ctx, decoded);
return JS_ThrowInternalError(ctx, "Invalid string");
} else if (!length) {
JS_FreeCString(ctx, decoded);
return JS_NewString(ctx, "");
}
int flen = 0;
char *encoded = base64(decoded, length, &flen);
JS_FreeCString(ctx, decoded);
JSValue result = JS_NewStringLen(ctx, encoded, flen);
free(encoded);
return result;
}
jsdec_t *jsdec_new() {
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
errorf("Error: failed to create qjs runtime\n");
return NULL;
}
JSContext *ctx = JS_NewContextRaw(rt);
if (!ctx) {
errorf("Error: failed to create qjs context\n");
JS_FreeRuntime(rt);
return NULL;
}
// initialize all intrisic
JS_AddIntrinsicBaseObjects(ctx);
JS_AddIntrinsicEval(ctx);
JS_AddIntrinsicRegExpCompiler(ctx);
JS_AddIntrinsicRegExp(ctx);
JS_AddIntrinsicJSON(ctx);
JS_AddIntrinsicTypedArrays(ctx);
JS_AddIntrinsicPromise(ctx);
JS_AddIntrinsicBigInt(ctx);
JS_AddIntrinsicDate(ctx);
// Setup global objects.
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global, "atob", JS_NewCFunction(ctx, js_atob, "atob", 1));
JS_SetPropertyStr(ctx, global, "btoa", JS_NewCFunction(ctx, js_btoa, "btoa", 1));
JSValue limits = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, global, "Limits", limits);
JS_SetPropertyStr(ctx, limits, "UT16_MAX", JS_NewBigUint64(ctx, 0xFFFFu));
JS_SetPropertyStr(ctx, limits, "UT32_MAX", JS_NewBigUint64(ctx, 0xFFFFFFFFu));
JS_SetPropertyStr(ctx, limits, "UT64_MAX", JS_NewBigUint64(ctx, 0xFFFFFFFFFFFFFFFFull));
JS_SetPropertyStr(ctx, limits, "ST16_MAX", JS_NewBigInt64(ctx, 0x7FFF));
JS_SetPropertyStr(ctx, limits, "ST32_MAX", JS_NewBigInt64(ctx, 0x7FFFFFFF));
JS_SetPropertyStr(ctx, limits, "ST64_MAX", JS_NewBigInt64(ctx, 0x7FFFFFFFFFFFFFFFull));
JS_FreeValue(ctx, global);
if (!js_load_all_modules(ctx)) {
errorf("Error: failed to load modules\n");
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return NULL;
}
jsdec_t *dec = malloc(sizeof(jsdec_t));
if (!dec) {
errorf("Error: failed to allocate jsdec_t\n");
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return NULL;
}
dec->context = ctx;
dec->runtime = rt;
return dec;
}
JSContext *jsdec_context(const jsdec_t *dec) {
return dec->context;
}
int jsdec_run(const jsdec_t *dec) {
return js_load_module(dec->context, main_bytecode, main_bytecode_size);
}
+17
View File
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#ifndef JSDEC_H
#define JSDEC_H
#include <quickjs.h>
typedef struct jsdec_s jsdec_t;
void jsdec_free(jsdec_t *dec);
jsdec_t *jsdec_new();
JSContext *jsdec_context(const jsdec_t *dec);
int jsdec_run(const jsdec_t *dec);
void jsdec_handle_exception(JSContext *ctx);
#endif /* JSDEC_H */
+28
View File
@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.12)
project(cutter-jsdec-plugin)
set(CMAKE_CXX_STANDARD 20)
set(CUTTER_INSTALL_PLUGDIR "share/rizin/cutter/plugins/native" CACHE STRING "Directory to install Cutter plugin into")
set(JSDEC_BUILD_DIR "../build" CACHE STRING "Directory where to find libjsdec.a")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/cmake/Cutter")
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_library(jsdec_cutter MODULE
JSDecPlugin.h
JSDecPlugin.cpp
JSDecDecompiler.h
JSDecDecompiler.cpp
)
find_library(libjsdec NAMES jsdec PATHS "${JSDEC_BUILD_DIR}")
include_directories("../include")
find_package(Cutter REQUIRED)
target_link_libraries(jsdec_cutter PRIVATE Cutter::Cutter "${libjsdec}")
install(TARGETS jsdec_cutter DESTINATION "${CUTTER_INSTALL_PLUGDIR}")
+40
View File
@@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: 2024 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#include "JSDecDecompiler.h"
#include <Cutter.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include "jsdec-cutter.h"
JSDecDecompiler::JSDecDecompiler(CutterCore *core)
: Decompiler("jsdec", "jsdec", core) {
task = nullptr;
RzCoreLocked c = core->core();
jsdec_init_config(c);
}
void JSDecDecompiler::decompileAt(RVA addr) {
if (task) {
return;
}
task = new RizinFunctionTask([addr](RzCore *core) {
return jsdec_as_annotation(core, addr);
});
connect(task, &RizinFunctionTask::finished, this, [this]() {
auto res = reinterpret_cast<RzAnnotatedCode *>(task->getResult());
delete task;
task = nullptr;
if (!res) {
res = Decompiler::makeWarning(tr("Failed to parse JSON from jsdec"));
}
emit finished(res);
});
task->startTask();
}
+21
View File
@@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2024 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#ifndef JSDEC_DECOMPILER_H
#define JSDEC_DECOMPILER_H
#include "Decompiler.h"
#include "RizinTask.h"
class JSDecDecompiler: public Decompiler
{
private:
RizinFunctionTask *task;
public:
JSDecDecompiler(CutterCore *core = nullptr);
virtual void decompileAt(RVA addr) override;
virtual bool isRunning() override { return task != nullptr; }
};
#endif // JSDEC_DECOMPILER_H
+18
View File
@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2024 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#include "JSDecDecompiler.h"
#include "JSDecPlugin.h"
void JSDecPlugin::setupPlugin()
{
}
void JSDecPlugin::setupInterface(MainWindow *)
{
}
void JSDecPlugin::registerDecompilers()
{
Core()->registerDecompiler(new JSDecDecompiler(Core()));
}
+29
View File
@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2024 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#ifndef JSDEC_CUTTER_PLUGIN_H
#define JSDEC_CUTTER_PLUGIN_H
#include <QObject>
#include <QtPlugin>
#include <plugins/CutterPlugin.h>
class JSDecPlugin : public QObject, CutterPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "re.rizin.cutter.plugins.jsdec")
Q_INTERFACES(CutterPlugin)
public:
void setupPlugin() override;
void setupInterface(MainWindow *main) override;
void registerDecompilers() override;
QString getName() const override { return "JsDec Decompiler (jsdec)"; }
QString getAuthor() const override { return "deroad"; }
QString getDescription() const override { return "GUI Integration of jsdec."; }
QString getVersion() const override { return "1.0"; }
};
#endif // JSDEC_CUTTER_PLUGIN_H
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/sh
find . -type f -name "*.js" | xargs eslint
find js/ -type f -name "*.js" | xargs eslint
+20
View File
@@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: 2024 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
#ifndef JSDEC_CUTTER_H
#define JSDEC_CUTTER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <rz_util/rz_annotated_code.h>
RZ_API void jsdec_init_config(RzCore *core);
RZ_API RzAnnotatedCode *jsdec_as_annotation(RzCore *core, ut64 addr);
#ifdef __cplusplus
}
#endif
#endif /* JSDEC_CUTTER_H */
+109
View File
@@ -0,0 +1,109 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-FileCopyrightText: 2017-2018 pancake <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import libdec from './libdec/libdec.js';
import rzutil from './libdec/rzutil.js';
import rzpipe from './libdec/rzpipe.js';
import Warning from './libdec/warning.js';
import Printer from './libdec/printer.js';
/**
* Shared data accessible from everywhere.
* @type {Object}
*/
var Shared = Global();
Shared.evars = null;
Shared.context = null;
Shared.printer = null;
Shared.argdb = null;
Shared.xrefs = null;
Shared.warning = Warning;
function decompile_offset(architecture, fcnname) {
var data = new rzutil.data();
Shared.argdb = data.argdb;
// af seems to break renaming.
/* asm.pseudo breaks things.. */
if (data.graph && data.graph.length > 0) {
var p = new libdec.core.session(data, architecture);
var arch_context = architecture.context(data);
libdec.core.analysis.pre(p, architecture, arch_context);
libdec.core.decompile(p, architecture, arch_context);
libdec.core.analysis.post(p, architecture, arch_context);
libdec.core.print(p);
} else if (Shared.evars.extra.allfunctions) {
Shared.context.printLog('Error: Please analyze the ' + fcnname + ' first.', true);
} else {
Shared.context.printLog('Error: no data available.\nPlease analyze the function/binary first.', true);
}
}
function main() {
var lines = null;
var errors = [];
var log = [];
try {
Shared.evars = rzutil.evars(process.args);
rzutil.sanitize(true, Shared.evars);
if (rzutil.check_args(process.args)) {
rzutil.sanitize(false, Shared.evars);
return;
}
// theme (requires to be initialized after evars)
Shared.printer = new Printer();
var architecture = libdec.archs[Shared.evars.arch];
if (architecture) {
Shared.context = new libdec.context();
var current = rzpipe.long('s');
if (Shared.evars.extra.allfunctions) {
var functions = rzpipe.json('aflj');
functions.forEach(function(x) {
if (x.name.startsWith('sym.imp.') || x.name.startsWith('loc.imp.')) {
return;
}
rzpipe.string('s 0x' + x.offset.toString(16));
Shared.context.printLine("", x.offset);
Shared.context.printLine(Shared.printer.theme.comment('/* name: ' + x.name + ' @ 0x' + x.offset.toString(16) + ' */'), x.offset);
decompile_offset(architecture, x.name);
});
rzpipe.string('s 0x' + current.toString(16));
var o = Shared.context;
Shared.context = new libdec.context();
Shared.context.macros = o.macros;
Shared.context.dependencies = o.dependencies;
Shared.context.printLine(Shared.printer.theme.comment('/* jsdec pseudo code output */'), current);
Shared.context.printLine(Shared.printer.theme.comment('/* ' + Shared.evars.extra.file + ' */'), current);
if (['java', 'dalvik'].indexOf(Shared.evars.arch) < 0) {
Shared.context.printMacros(true);
Shared.context.printDependencies(true);
}
o.lines = Shared.context.lines.concat(o.lines);
Shared.context = o;
} else {
decompile_offset(architecture, null);
}
errors = errors.concat(Shared.context.errors);
log = log.concat(Shared.context.log);
lines = Shared.context.lines;
} else {
errors.push(Shared.evars.arch + ' is not currently supported.\n' +
'Please open an enhancement issue at https://github.com/rizinorg/jsdec/issues\n' +
libdec.supported());
}
rzutil.sanitize(false, Shared.evars);
} catch (e) {
errors.push(rzutil.debug(Shared.evars, e));
}
if (!Shared.printer) {
Shared.printer = new Printer();
}
Shared.printer.flushOutput(lines, errors, log);
}
main();
+38
View File
@@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import libdec from './libdec/libdec.js';
import Printer from './libdec/printer.js';
import TestSuite from './libdec/testsuite.js';
function main() {
try {
const test = new TestSuite();
var Shared = Global();
Shared.evars = test.evars;
Shared.argdb = test.data.argdb;
Shared.printer = new Printer();
Shared.context = new libdec.context();
var architecture = libdec.archs[Shared.evars.arch];
// af seems to break renaming.
/* asm.pseudo breaks things.. */
if (test.data.graph && test.data.graph.length > 0) {
var p = new libdec.core.session(test.data, architecture, Shared.evars);
var arch_context = architecture.context(test.data);
libdec.core.analysis.pre(p, architecture, arch_context);
libdec.core.decompile(p, architecture, arch_context);
libdec.core.analysis.post(p, architecture, arch_context);
libdec.core.print(p);
Shared.printer.flushOutput(Shared.context.lines, Shared.context.errors, Shared.context.log, Shared.evars.extra);
} else {
console.log('Error: no data available.\nPlease analyze the function/binary first.');
}
} catch (e) {
const error = 'Exception: ' + e.message + ' (' + e.name + ')\n' + e.stack;
const filename = unit.file.split('/').slice(-1)[0];
console.log('File:', filename);
console.log(error);
}
}
main();
+331
View File
@@ -0,0 +1,331 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Long from './long.js';
var json_parse = function(options) {
"use strict";
// This is a function that can parse a JSON text, producing a JavaScript
// data structure. It is a simple, recursive descent parser. It does not use
// eval or regular expressions, so it can be used as a model for implementing
// a JSON parser in other languages.
// We are defining the function inside of another function to avoid creating
// global variables.
var at, // The index of the current character
ch, // The current character
escapee = {
'"': '"',
'\\': '\\',
'/': '/',
b: '\b',
f: '\f',
n: '\n',
r: '\r',
t: '\t'
},
text,
error = function(m) {
// Call error when something is wrong.
throw {
name: 'SyntaxError',
message: m,
at: at,
text: text
};
},
next = function(c) {
// If a c parameter is provided, verify that it matches the current character.
if (c && c !== ch) {
error("Expected '" + c + "' instead of '" + ch + "'");
}
// Get the next character. When there are no more characters,
// return the empty string.
ch = text.charAt(at);
at += 1;
return ch;
},
number = function() {
// Parse a number value.
var number,
string = '';
if (ch === '-') {
string = '-';
next('-');
}
while (ch >= '0' && ch <= '9') {
string += ch;
next();
}
if (ch === '.') {
string += '.';
while (next() && ch >= '0' && ch <= '9') {
string += ch;
}
}
if (ch === 'e' || ch === 'E') {
string += ch;
next();
if (ch === '-' || ch === '+') {
string += ch;
next();
}
while (ch >= '0' && ch <= '9') {
string += ch;
next();
}
}
number = +string;
if (!isFinite(number)) {
error("Bad number");
} else {
if (string.indexOf('.') < 0) {
try {
return Long.from(string, true);
} catch (e) {
console.log(e.message);
console.log(e.stack);
return string;
}
}
return number;
}
},
string = function() {
// Parse a string value.
var hex,
i,
string = '',
uffff;
// When parsing for string values, we must look for " and \ characters.
if (ch === '"') {
while (next()) {
if (ch === '"') {
next();
return string;
}
if (ch === '\\') {
next();
if (ch === 'u') {
uffff = 0;
for (i = 0; i < 4; i += 1) {
hex = parseInt(next(), 16);
if (!isFinite(hex)) {
break;
}
uffff = uffff * 16 + hex;
}
string += String.fromCharCode(uffff);
} else if (typeof escapee[ch] === 'string') {
string += escapee[ch];
} else {
break;
}
} else {
string += ch;
}
}
}
error("Bad string");
},
white = function() {
// Skip whitespace.
while (ch && ch <= ' ') {
next();
}
},
word = function() {
// true, false, or null.
switch (ch) {
case 't':
next('t');
next('r');
next('u');
next('e');
return true;
case 'f':
next('f');
next('a');
next('l');
next('s');
next('e');
return false;
case 'n':
next('n');
next('u');
next('l');
next('l');
return null;
}
error("Unexpected '" + ch + "'");
},
value, // Place holder for the value function.
array = function() {
// Parse an array value.
var array = [];
if (ch === '[') {
next('[');
white();
if (ch === ']') {
next(']');
return array; // empty array
}
while (ch) {
array.push(value());
white();
if (ch === ']') {
next(']');
return array;
}
next(',');
white();
}
}
error("Bad array");
},
object = function() {
// Parse an object value.
var key,
object = {};
if (ch === '{') {
next('{');
white();
if (ch === '}') {
next('}');
return object; // empty object
}
while (ch) {
key = string();
white();
next(':');
object[key] = value();
white();
if (ch === '}') {
next('}');
return object;
}
next(',');
white();
}
}
error("Bad object");
};
value = function() {
// Parse a JSON value. It could be an object, an array, a string, a number,
// or a word.
white();
switch (ch) {
case '{':
return object();
case '[':
return array();
case '"':
return string();
case '-':
return number();
default:
return ch >= '0' && ch <= '9' ? number() : word();
}
};
// Return the json_parse function. It will have access to all of the above
// functions and variables.
return function(source, reviver) {
var result;
text = source + '';
at = 0;
ch = ' ';
result = value();
white();
if (ch) {
error("Syntax error");
}
// If there is a reviver function, we recursively walk the new structure,
// passing each name/value pair to the reviver function for possible
// transformation, starting with a temporary root object that holds the result
// in an empty key. If there is not a reviver function, we simply return the
// result.
return typeof reviver === 'function' ? (function walk(holder, key) {
var v, value = holder[key];
if (value && typeof value === 'object') {
Object.keys(value).forEach(function(k) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
});
}
return reviver.call(holder, key, value);
}({
'': result
}, '')) : result;
};
};
function _iterate_value(variable, pad, depth, used) {
if (used.indexOf(variable) >= 0) {
return null;
}
var spad = pad.repeat(depth);
var nl = pad.length > 0 ? "\n" : "";
var sp = "\"";
var k, sval, str = "";
var comma = false;
if (Array.isArray(variable)) {
used.push(variable);
if (variable.length < 1) {
return "[]";
}
str = "[" + nl;
for (k = 0; k < variable.length; k++) {
sval = _iterate_value(variable[k], pad, depth + 1, used);
if (sval) {
comma = true;
str += spad + sval + "," + nl;
}
}
if (comma) {
str = str.slice(0, 0 - ("," + nl).length) + nl;
str += pad.repeat(depth - 1) + "]";
} else {
str = str.slice(0, -1) + "]";
}
return str;
} else if (["number", "bigint"].indexOf(typeof variable) >= 0) {
return variable.toString(10);
} else if (Long.isLong(variable)) {
return variable.toString(10);
} else if (typeof variable == "function") {
return null;
} else if (typeof variable == "object") {
used.push(variable);
str = "{" + nl;
for (k in variable) {
sval = _iterate_value(variable[k], pad, depth + 1, used);
if (sval) {
comma = true;
str += spad + sp + k + sp + ":" + sval + "," + nl;
}
}
if (comma) {
str = str.slice(0, 0 - ("," + nl).length) + nl;
str += pad.repeat(depth - 1) + "}";
} else {
str = str.slice(0, -1) + "}";
}
return str;
} else {
//console.log(typeof variable)
return JSON.stringify(variable);
}
}
function stringify(variable, pad) {
pad = pad ? pad : "";
return _iterate_value(variable, pad, 1, []);
}
export default {
parse: json_parse(),
stringify: stringify
};
+183
View File
@@ -0,0 +1,183 @@
// SPDX-FileCopyrightText: 2020-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import rzutil from './rzutil.js';
import Strings from './core/strings.js';
import Functions from './core/functions.js';
import Extra from './core/extra.js';
import Long from './long.js';
const _re_keywords = /\bif\b|\belse\b|\bwhile\b|\bfor\b|\bdo\b|\breturn\b|\bthrow\b|\bnew\b|\b__asm\b/g;
const _re_types = /\b[ui]+nt[123468]+_t\b|\bvoid\b|\bconst\b|\bsizeof\b|\bfloat\b|\bdouble\b|\bchar\b|\bwchar_t\b|\bextern\b|\bstruct\b|\bsize_t\b|\btime_t\b|\bboolean\b/g;
const _re_numbers = /\b0x[0-9a-fA-F]+\b|\b\d+\b/g;
const _re_string = /"[^"]+"/;
const _re_objcall = /[\w.]+\s?\([^)]+\)|[\w.]+\s?\(\)/;
function Annotation(start, length, value, pointer, type, syntax_type) {
this.start = start;
this.end = start + length;
this.type = type;
if (["function_name", "function_parameter", "local_variable"].indexOf(this.type) >= 0) {
this.name = value;
}
if (["function_name", "offset", "global_variable", "constant_variable"].indexOf(this.type) >= 0) {
this.offset = pointer.toString();
}
if (this.type == "syntax_highlight") {
this.syntax_highlight = syntax_type;
}
}
function _sort_by_start(x, y) {
if (x.start == y.start) {
if (x.type == "offset") {
return -1;
} else if (x.type == "syntax_highlight") {
return 0;
}
return 1;
}
return x.start - y.start;
}
function _match_annotation(regex, line, callback) {
var tokens, matches;
matches = line.match(regex);
tokens = line.split(regex);
if (!matches) {
return;
}
for (var i = 0, pos = 0; i < matches.length; i++) {
pos += tokens[i].length;
callback(pos, matches[i]);
pos += matches[i].length;
}
}
export default {
context: function() {
var data = new rzutil.data(false);
return {
comment: false,
arch: data.arch,
strings: new Strings(data.xrefs.strings, true).data,
functions: new Functions(data.xrefs.functions, true).data.map(function(x) {
return {
location: x.offset,
value: Extra.replace.call(x.name),
name: x.name
};
}),
variables: data.arch == "dalvik" ? [] : Array.prototype.concat(data.xrefs.arguments.stack, data.xrefs.arguments.reg)
};
},
parse: function(current, line, context) {
var pos, old, i, a = [],
it, tmp, ll = line.str.length;
var string_beg = ll,
string_end = -1;
a.push(new Annotation(current, ll, null, line.offset, "offset"));
if (line.str.trim().startsWith('/*') || context.comment) {
context.comment = !line.str.endsWith('*/');
a.push(new Annotation(current, ll, line.str, null, "syntax_highlight", "comment"));
return a;
} else if (line.str.startsWith('//')) {
a.push(new Annotation(current, ll, line.str, null, "syntax_highlight", "comment"));
return a;
} else if (line.str.startsWith('#')) {
a.push(new Annotation(current, ll, line.str, null, "syntax_highlight", "comment"));
return a;
}
/* strings */
for (i = context.strings.length - 1; i >= 0; i--) {
it = context.strings[i];
var str = '"' + it.value + '"';
pos = line.str.indexOf(str);
if (pos > 0) {
// include the ""
a.push(new Annotation(current + pos, str.length, str, it.location, "global_variable", null));
a.push(new Annotation(current + pos, str.length, str, null, "syntax_highlight", "global_variable"));
string_beg = pos;
string_end = string_beg + str.length;
break;
}
}
/* strings with regex */
if (string_end < 0) {
tmp = line.str.match(_re_string) || [];
for (i = tmp.length - 1, old = 0; i >= 0; i--) {
pos = line.str.indexOf(tmp[i]);
a.push(new Annotation(current + pos, tmp[i].length, tmp[i], null, "syntax_highlight", "global_variable"));
string_beg = pos;
string_end = pos + tmp[i].length;
break;
}
}
/* function names */
if (context.arch == "dalvik") {
pos = line.str.search(_re_objcall);
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
var callname = line.str.substr(pos, line.str.substr(pos).indexOf('(')).trim();
if (['__asm'].indexOf(callname) < 0) {
a.push(new Annotation(current + pos, callname.length, callname, null, "syntax_highlight", "function_name"));
}
}
} else {
for (i = context.functions.length - 1; i >= 0; i--) {
it = context.functions[i];
pos = line.str.search(new RegExp('\\b' + it.value + '\\b'));
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, it.value.length, it.name, it.location, "function_name", null));
a.push(new Annotation(current + pos, it.value.length, it.value, null, "syntax_highlight", "function_name"));
break;
}
}
}
/* variables */
for (i = context.variables.length - 1, old = 0; i >= 0; i--) {
it = context.variables[i];
if (!it) {
continue;
}
pos = it.type.match(_re_types) ? -1 : line.str.search(new RegExp('\\b' + it.type + '\\b'));
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, it.type.length, it.type, null, "syntax_highlight", "datatype"));
}
pos = line.str.search(new RegExp('\\b' + it.name + '\\b'));
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
var type = (it.kind === 'arg' || it.kind === 'reg') ? "function_parameter" : "local_variable";
a.push(new Annotation(current + pos, it.name.length, it.name, line.offset, type, null));
a.push(new Annotation(current + pos, it.name.length, it.name, null, "syntax_highlight", type));
}
}
/* keywords */
_match_annotation(_re_keywords, line.str, function(pos, match) {
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, match.length, match, null, "syntax_highlight", "keyword"));
}
});
/* numbers */
_match_annotation(_re_numbers, line.str, function(pos, match) {
if (match.length > 1 && match.charAt(0) == '0' && match.charAt(1) != 'x') {
return;
}
if (match != '0') {
pos = old + line.str.substr(old, ll).indexOf(match);
} else {
pos = old + line.str.substr(old, ll).search(/\b0\b/);
}
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
var location = Long.from(match);
a.push(new Annotation(current + pos, match.length, match, location, "constant_variable", null));
a.push(new Annotation(current + pos, match.length, match, null, "syntax_highlight", "constant_variable"));
}
});
/* types */
_match_annotation(_re_types, line.str, function(pos, match) {
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, match.length, match, null, "syntax_highlight", "datatype"));
}
});
return a.sort(_sort_by_start);
}
};
+387
View File
@@ -0,0 +1,387 @@
// SPDX-FileCopyrightText: 2019-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from '../core/base.js';
import Variable from '../core/variable.js';
const _REG = {
X: 'x',
Y: 'y',
stackptr: 'SP',
accumulator: 'acc',
carry: 'C',
overflow: 'V',
decimal: 'D',
interrupt: 'I',
zero: 'Z',
};
function _arg(instr, idx) {
var o = instr.parsed.opd;
if (idx > 0) {
return o[idx];
}
o = o[0];
if (o.immediate) {
return o.token;
}
return Variable.pointer(o.token, 16, false);
}
function _math(op, instr, bits) {
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
if (!srcB) {
return op(_REG.accumulator, _REG.accumulator, srcA, bits);
}
return Base.composed([
op(_REG.accumulator, _REG.accumulator, srcA, bits),
Base.add(_REG.accumulator, _REG.accumulator, srcB),
]);
}
function _math_rotate(op, instr, bits) {
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
if (!srcB) {
// destination, source_a, source_b, bits
return op(_REG.accumulator, srcA, bits, 16);
}
return Base.composed([
op(_REG.accumulator, srcA, bits, 16),
Base.add(_REG.accumulator, _REG.accumulator, srcB),
]);
}
function _load(instr, register, bits) {
bits = bits || 16;
register = register || _REG.accumulator;
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
var ops = [];
if (typeof srcA == "string") {
// pointer, register, bits, is_signed
ops.push(Base.read_memory(register, register, srcA, bits));
} else {
ops.push(Base.assign(register, srcA));
}
if (!srcB) {
return ops[0];
}
ops.push(Base.add(register, register, srcB));
return Base.composed(ops);
}
function _store(instr, register, bits) {
bits = bits || 16;
register = register || _REG.accumulator;
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
var ops = [];
if (typeof srcA == "string") {
// pointer, register, bits, is_signed
ops.push(Base.write_memory(register, register, srcA, bits));
} else {
ops.push(Base.assign(srcA, register));
}
if (!srcB) {
return ops[0];
}
ops.push(Base.add(register, register, srcB));
return Base.composed(ops);
}
function _nop(instr, context, instructions) {
return Base.nop();
}
export default {
instructions: {
adc: function(instr) {
return _math(Base.add, instr);
},
and: function(instr) {
return _math(Base.and, instr);
},
asl: function(instr) {
return _math(Base.shift_left, instr, 1);
},
bit: function(instr, context) {
var p = _arg(instr, 0);
context.cond.a = '(' + _REG.accumulator + ' & ' + p + ')';
context.cond.b = '0';
return Base.nop();
},
bcc: function(instr, context) {
instr.conditional(_REG.carry, 0, 'EQ');
return Base.nop();
},
bcs: function(instr, context) {
instr.conditional(_REG.carry, 0, 'NE');
return Base.nop();
},
beq: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'EQ');
return Base.nop();
},
bmi: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'LT');
return Base.nop();
},
bne: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'NE');
return Base.nop();
},
bpl: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'GT');
return Base.nop();
},
brk: function(instr, context) {
Global().context.addMacro('#define INTERRUPT() __asm(brk)');
return Base.call(Variable.macro('INTERRUPT'), []);
},
bvc: function(instr, context) {
instr.conditional(_REG.overflow, 0, 'EQ');
return Base.nop();
},
bvs: function(instr, context) {
instr.conditional(_REG.overflow, 0, 'NE');
return Base.nop();
},
clc: function(instr, context) {
return Base.assign(_REG.carry, '0');
},
cld: function(instr, context) {
return Base.assign(_REG.decimal, '0');
},
cli: function(instr, context) {
return Base.assign(_REG.interrupt, '0');
},
clv: function(instr, context) {
return Base.assign(_REG.overflow, '0');
},
cmp: function(instr, context) {
instr.setBadJump();
context.cond.a = _REG.accumulator;
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
if (!srcB) {
context.cond.b = srcA;
return Base.nop();
}
var v = Variable.uniqueName();
context.cond.b = v;
return Base.add(v, srcA, srcB);
},
cpx: function(instr, context) {
instr.setBadJump();
context.cond.a = _REG.X;
context.cond.b = _arg(instr, 0);
return Base.nop();
},
cpy: function(instr, context) {
instr.setBadJump();
context.cond.a = _REG.Y;
context.cond.b = _arg(instr, 0);
return Base.nop();
},
dec: function(instr, context) {
var p = _arg(instr, 0);
context.cond.a = p;
context.cond.b = '0';
return Base.subtract(p, p, 1);
},
dex: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.subtract(_REG.X, _REG.X, 1);
},
dey: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
return Base.subtract(_REG.Y, _REG.Y, 1);
},
eor: function(instr, context) {
return _math(Base.xor, instr);
},
inc: function(instr, context) {
var p = _arg(instr, 0);
context.cond.a = p;
context.cond.b = '0';
return Base.add(p, p, 1);
},
inx: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.add(_REG.X, _REG.X, 1);
},
iny: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
return Base.add(_REG.Y, _REG.Y, 1);
},
jmp: _nop,
jsr: function(instr) {
var p = instr.parsed.opd[0].token;
if (p.startsWith('0x')) {
p = Variable.functionPointer(p);
}
return Base.call(p);
},
lda: function(instr, context) {
context.cond.a = _REG.accumulator;
context.cond.b = '0';
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(_REG.accumulator, instr.parsed.opd[0].token.replace(/^sym\./, ''));
}
return _load(instr, _REG.accumulator, 16);
},
ldx: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(_REG.X, instr.parsed.opd[0].token.replace(/^sym\./, ''));
}
return _load(instr, _REG.X, 16);
},
ldy: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(_REG.Y, instr.parsed.opd[0].token.replace(/^sym\./, ''));
}
return _load(instr, _REG.Y, 16);
},
lsr: function(instr) {
return _math(Base.shift_right, instr, 1);
},
ora: function(instr, context) {
return _math(Base.xor, instr);
},
pha: _nop,
php: _nop,
pla: _nop,
plp: _nop,
rol: function(instr) {
return _math_rotate(Base.rotate_left, instr, 1);
},
ror: function(instr) {
return _math_rotate(Base.rotate_right, instr, 1);
},
rti: function(instr) {
return Base.return();
},
rts: function(instr) {
return Base.return();
},
sbc: function(instr) {
return _math(Base.subtract, instr);
},
sec: function(instr, context) {
return Base.assign(_REG.carry, 1);
},
sed: function(instr, context) {
return Base.assign(_REG.decimal, 1);
},
sei: function(instr, context) {
return Base.assign(_REG.interrupt, 1);
},
sta: function(instr) {
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(instr.parsed.opd[0].token.replace(/^sym\./, ''), _REG.accumulator);
}
return _store(instr, _REG.accumulator, 16);
},
stx: function(instr) {
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(instr.parsed.opd[0].token.replace(/^sym\./, ''), _REG.X);
}
return _store(instr, _REG.X, 16);
},
sty: function(instr) {
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(instr.parsed.opd[0].token.replace(/^sym\./, ''), _REG.Y);
}
return _store(instr, _REG.Y, 16);
},
tax: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.assign(_REG.X, _REG.accumulator);
},
tay: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
return Base.assign(_REG.Y, _REG.accumulator);
},
tsx: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.assign(_REG.X, _REG.stackptr);
},
txs: function(instr, context) {
return Base.assign(_REG.stackptr, _REG.X);
},
txa: function(instr, context) {
context.cond.a = _REG.accumulator;
context.cond.b = '0';
return Base.assign(_REG.accumulator, _REG.X);
},
tya: function(instr, context) {
context.cond.a = _REG.accumulator;
context.cond.b = '0';
return Base.assign(_REG.accumulator, _REG.Y);
},
nop: _nop,
invalid: _nop
},
parse: function(assembly) {
var tokens = assembly.trim().match(/^([\w]+) ?(#)?(\()?((0x[\da-fA-F]+)|([a-zA-Z0-9._]+))?(\))?(,([\w]+))?\)?$/);
var opds = [];
if (tokens[5] || tokens[6]) {
var token = tokens[5] || tokens[6];
if (tokens[3] == '(' && tokens[7] == ')' && tokens[9]) {
token += ' + ' + tokens[9];
}
opds.push({
immediate: tokens[2] == '#',
pointer: tokens[3] == '(',
token: token,
});
}
if (tokens[9] && tokens[3] == '(' && tokens[7] != ')') {
opds.push(tokens[9]);
}
return {
mnem: tokens[1],
opd: opds
};
},
context: function() {
return {
cond: {
a: _REG.accumulator,
b: '?',
}
};
},
preanalisys: function(instructions, context) {},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
+277
View File
@@ -0,0 +1,277 @@
// SPDX-FileCopyrightText: 2021-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from '../core/base.js';
import Variable from '../core/variable.js';
const EXTRAM = "eram + ";
const INDRAM = "iram + ";
function resolve_opd(instr, index) {
var a = instr.parsed.opd[index].replace(/\+/, ' + ');
if (a.indexOf('#') == 0) {
return a.substr(1, a.length);
} else if (a.match(/^\d+$|^0x[a-fA-F\d]+$/)) {
return Variable.pointer(INDRAM + a, 8, false);
} else if (a.indexOf('@') == 0) {
return Variable.pointer(EXTRAM + a.substr(1, a.length), 8, false);
}
return a;
}
function previous(instr, instructions) {
return instructions[instructions.indexOf(instr) - 1];
}
function is_mnem(instr, mnem, startswith) {
if (startswith) {
return instr && instr.parsed.mnem.indexOf(mnem) == 0;
}
return instr && instr.parsed.mnem == mnem;
}
function is_last(instr, instructions) {
return instructions.indexOf(instr) == (instructions.length - 1);
}
function is_membit(instr, index) {
return instr.parsed.opd[index].indexOf('.') > 0;
}
function write_membit(instr, index, b) {
var a = instr.parsed.opd[index].split('.');
var p = Variable.pointer(a[0], 8, false);
if (b == '1') {
b = '0x' + (1 << parseInt(a[1])).toString(16);
} else if (b != '0') {
b = '(' + b + ' & 1)' + (parseInt(a[1]) > 0 ? ' << ' + a[1] : '');
} else {
var bit = parseInt(a[1]) < 1 ? '~1' : '~(1 << ' + a[1] + ')';
return Base.and(p, p, bit);
}
return Base.or(p, p, b);
}
function read_membit(instr, index, b) {
var a = instr.parsed.opd[index].split('.');
var p = Variable.pointer(a[0], 8, false);
if (parseInt(a[1]) < 1) {
return Base.and(b, p, '1');
}
return Base.assign(b, '(' + p.toString() + ' >> ' + a[1] + ') & 1');
}
function _mov(instr, context, instructions) {
if (is_membit(instr, 0)) {
return write_membit(instr, 0, resolve_opd(instr, 1));
} else if (is_membit(instr, 1)) {
return read_membit(instr, 1, resolve_opd(instr, 0));
}
var a = resolve_opd(instr, 0);
var b = resolve_opd(instr, 1);
return Base.assign(a, b);
}
function _call(instr, context, instructions) {
var args = [];
var prev = previous(instr, instructions);
if (prev && prev.parsed.opd[0] == 'a') {
args.push(prev.parsed.opd[0]);
}
return Base.call(instr.parsed.opd[0], args);
}
function _jump(instr, context, instructions) {
if (is_last(instr, instructions) &&
(instr.jump.gt(instr.location) || instr.jump.lt(instructions[0].location))) {
return _call(instr, context, instructions);
}
return Base.nop();
}
function _math(instr, context, op, carry) {
if (carry) {
return op('a', op(resolve_opd(instr, 0), resolve_opd(instr, 1)), 'carry');
}
return op('a', resolve_opd(instr, 0), resolve_opd(instr, 1));
}
function _nop(instr, context, instructions) {
return Base.nop();
}
export default {
instructions: {
acall: _call,
add: function(instr, context, instructions) {
return _math(instr, context, Base.add);
},
addc: function(instr, context, instructions) {
instr.comments.push("add with carry");
return _math(instr, context, Base.add, true);
},
ajmp: _jump,
anl: function(instr, context, instructions) {
return _math(instr, context, Base.and);
},
cjne: function(instr, context, instructions) {
instr.conditional(resolve_opd(instr, 0), resolve_opd(instr, 1), 'NE');
return Base.nop();
},
clr: function(instr, context, instructions) {
if (is_membit(instr, 0)) {
return write_membit(instr, 0, '0');
}
return Base.assign(resolve_opd(instr, 0), '0');
},
cpl: function(instr, context, instructions) {
return Base.not(instr.parsed.opd[0], instr.parsed.opd[0]);
},
dec: function(instr, context, instructions) {
return Base.decrease(resolve_opd(instr, 0), '1');
},
div: function(instr, context, instructions) {
return Base.divide('a', 'a', 'b');
},
djnz: function(instr, context, instructions) {
var a = resolve_opd(instr, 0);
instr.conditional(a, '0', 'NE');
return Base.decrease(a, '1');
},
inc: function(instr, context, instructions) {
return Base.increase(resolve_opd(instr, 0), '1');
},
jb: function(instr, context, instructions) {
instr.conditional('b', '0', 'NE');
return Base.nop();
},
jbc: function(instr, context, instructions) {
instr.conditional('b', '0 && c', 'NE');
return Base.nop();
},
jc: function(instr, context) {
instr.conditional('c', '0', 'NE');
return Base.nop();
},
jmp: _jump,
jnb: function(instr, context, instructions) {
instr.conditional('b', '0', 'EQ');
return Base.nop();
},
jnc: function(instr, context, instructions) {
instr.conditional('c', '0', 'EQ');
return Base.nop();
},
jnz: function(instr, context, instructions) {
var p = previous(instr, instructions);
instr.conditional(is_mnem(p, 'mov', true) ? resolve_opd(p, 1) : 'a', '0', 'NE');
return Base.nop();
},
jz: function(instr, context, instructions) {
var p = previous(instr, instructions);
instr.conditional(is_mnem(p, 'mov', true) ? resolve_opd(p, 1) : 'a', '0', 'EQ');
return Base.nop();
},
lcall: _call,
ljmp: _jump,
mov: _mov,
movc: _mov,
movx: _mov,
mul: function(instr, context, instructions) {
return Base.multiply('a', 'a', 'b');
},
orl: function(instr, context, instructions) {
return _math(instr, context, Base.or);
},
pop: function(instr) {
return Base.assign(resolve_opd(instr, 0), Base.call('pop', []));
},
push: function(instr) {
return Base.call('push', [resolve_opd(instr, 0)]);
},
ret: function(instr) {
return Base.return();
},
reti: function(instr) {
return Base.return();
},
rl: function(instr) {
return Base.rotate_left('a', 'a', '1', 8);
},
rlc: function(instr) {
instr.comments.push("rotate with carry");
return Base.rotate_left('a', 'a', '1', 8);
},
rr: function(instr) {
return Base.rotate_right('a', 'a', '1', 8);
},
rrc: function(instr) {
instr.comments.push("rotate with carry");
return Base.rotate_right('a', 'a', '1', 8);
},
setb: function(instr, context, instructions) {
if (is_membit(instr, 0)) {
return write_membit(instr, 0, '1');
}
return Base.assign(instr.parsed.opd[0], 1);
},
sjmp: _jump,
subb: function(instr, context, instructions) {
return _math(instr, context, Base.subtract);
},
swap: function(instr, context, instructions) {
return Base.swap_endian(resolve_opd(instr, 1), resolve_opd(instr, 0), 8);
},
xch: function(instr, context, instructions) {
return Base.swap(resolve_opd(instr, 0), resolve_opd(instr, 1), 8);
},
xchd: function(instr, context, instructions) {
var a = resolve_opd(instr, 0);
var b = resolve_opd(instr, 1);
var tmp = Variable.uniqueName('tmp');
var ops = [
Base.and(tmp, a, '0xF'),
Base.and(a, a, '0xF0'),
Base.or(a, b, '0xF0'),
Base.and(b, b, '0xF0'),
Base.or(b, b, tmp),
];
context.local.push(tmp);
return Base.composed(ops);
},
xrl: function(instr, context, instructions) {
return _math(instr, context, Base.xor);
},
nop: _nop,
reserved: _nop,
invalid: _nop
},
parse: function(assembly) {
assembly = assembly.trim().replace(/,/g, '');
var tokens = assembly.split(' ');
return {
mnem: tokens[0],
opd: tokens.splice(1)
};
},
context: function() {
return {
local: []
};
},
preanalisys: function(instructions, context) {},
localvars: function(context) {
return context.local.map(function(x) {
return 'uint8_t ' + x;
});
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
File diff suppressed because it is too large. Load diff
+673
View File
@@ -0,0 +1,673 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from '../core/base.js';
import Variable from '../core/variable.js';
const AVR_MEM_BITS = 16;
const AVR_X_MACRONAME = 'MEM_X';
const AVR_Y_MACRONAME = 'MEM_Y';
const AVR_Z_MACRONAME = 'MEM_Z';
const AVR_X_MACRO = '#define ' + AVR_X_MACRONAME + ' ((uint16_t*)((r27 << 8) | r26))';
const AVR_Y_MACRO = '#define ' + AVR_Y_MACRONAME + ' ((uint16_t*)((r29 << 8) | r28))';
const AVR_Z_MACRO = '#define ' + AVR_Z_MACRONAME + ' ((uint16_t*)((r31 << 8) | r30))';
const AVR_MEMORY = {
'x': {
name: AVR_X_MACRONAME,
macro: AVR_X_MACRO,
high: 'r27',
low: 'r26'
},
'y': {
name: AVR_Y_MACRONAME,
macro: AVR_Y_MACRO,
high: 'r29',
low: 'r28'
},
'z': {
name: AVR_Z_MACRONAME,
macro: AVR_Z_MACRO,
high: 'r31',
low: 'r30'
}
};
var AVR_CTR = 0;
var _to_16bit = function(high, low) {
if ((high == '0x00' || high == '0') && (low == '0x00' || low == '0')) {
return '0';
} else if (low == '0x00' || low == '0') {
return '(' + high + ' << 8)';
} else if (high == '0x00' || high == '0') {
return low;
}
return '(' + low + ' | (' + high + ' << 8))';
};
var _common_math = function(instr, op) {
instr.setBadJump();
var e = instr.parsed.opd;
return op(e[0], e[0], e[1]);
};
var _compare = function(a, b, context) {
context.cond.a = a;
context.cond.b = b;
};
var _compare_values = function(a1, b1, a2, b2, context) {
context.cond.a = _to_16bit(a2, a1);
context.cond.b = _to_16bit(b2, b1);
};
var _compare_bytes = function(a, b, context) {
var a1 = context.cond.a;
var b1 = context.cond.b;
_compare_values(a1, b1, a, b, context);
};
var _conditional = function(instr, context, type) {
instr.conditional(context.cond.a, context.cond.b, type);
if (context.cond.instr) {
context.cond.instr.valid = false;
}
};
var _next_register = function(reg) {
var num = parseInt(reg.substr(1, reg.length)) + 1;
return 'r' + num;
};
var _returns_r0 = function(instr, context, inverted) {
if (inverted && instr.parsed.opd[1] == 'r0') {
context.returns = 'r0';
} else if (!inverted && instr.parsed.opd[0] == 'r0') {
context.returns = 'r0';
}
};
var _conditional_next = function(instr, context, instructions, type) {
instr.conditional(context.cond.a, context.cond.b, type);
var next = instructions[instructions.indexOf(instr) + 1];
if (next) {
instr.jump = next.location;
}
if (context.cond.instr) {
context.cond.instr.valid = false;
}
};
var _load16 = function(instr, context) {
var v, m, op;
_returns_r0(instr, context);
var ptr = instr.parsed.opd[1];
if (ptr.indexOf('-') >= 0) {
ptr = ptr.replace('-', '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.read_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[0], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.subtract(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '-')
];
op = Base.composed(m);
Global().context.addMacro(AVR_MEMORY[ptr].macro);
return op;
} else if (ptr.indexOf('+') >= 0) {
ptr = ptr.replace('+', '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.read_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[0], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.add(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '+')
];
op = Base.composed(m);
Global().context.addMacro(AVR_MEMORY[ptr].macro);
return op;
}
//pointer, register, bits, is_signed
op = Base.read_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[0], 8, false);
Global().context.addMacro(AVR_MEMORY[ptr].macro);
return op;
};
var _store16 = function(instr, context) {
var v, m, op;
instr.setBadJump();
_returns_r0(instr, context);
var ptr = instr.parsed.opd[0];
if (ptr.indexOf('-') >= 0) {
ptr = ptr.replace(/-\d?/, '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.write_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[1], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.subtract(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '-')
];
op = Base.composed(m);
Global().context.addMacro(AVR_MEMORY[ptr].macro);
return op;
} else if (ptr.indexOf('+') >= 0) {
ptr = ptr.replace(/\+\d?/, '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.write_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[1], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.add(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '+')
];
op = Base.composed(m);
Global().context.addMacro(AVR_MEMORY[ptr].macro);
return op;
}
//pointer, register, bits, is_signed
op = Base.write_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[1], 8, false);
Global().context.addMacro(AVR_MEMORY[ptr].macro);
return op;
};
export default {
instructions: {
adc: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.add);
},
add: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.add);
},
adiw: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
var b = instr.parsed.opd[1];
var a1 = instr.parsed.opd[0];
var a2 = _next_register(instr.parsed.opd[0]);
_compare_values(a1, b, a2, b, context);
context.cond.instr = instr;
if (b == '0x00' || b == '0') {
return Base.nop();
}
var op1 = null;
var op2 = null;
if (b == '0x01' || b == '1') {
op1 = Base.increase(a1, '1');
op2 = Base.increase(a2, '1');
} else {
op1 = Base.add(a1, a1, b);
op2 = Base.add(a2, a2, b);
}
return Base.composed([op1, op2]);
},
and: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.and);
},
andi: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.and);
},
asr: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.shift_right(instr.parsed.opd[0], instr.parsed.opd[0], '1');
},
brbc: function(instr, context) {
_returns_r0(instr, context);
var old_b = context.cond.b;
context.cond.b = '0';
_conditional(instr, context, 'NE');
context.cond.b = old_b;
return Base.nop();
},
brbs: function(instr, context) {
_returns_r0(instr, context);
var old_b = context.cond.b;
context.cond.b = '(1 << ' + instr.parsed.opd[0] + ')';
_conditional(instr, context, 'NE');
context.cond.b = old_b;
return Base.nop();
},
brcc: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'GE');
return Base.nop();
},
brcs: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
breq: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'EQ');
return Base.nop();
},
brlo: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
brlt: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
brmi: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
brne: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'NE');
return Base.nop();
},
brpl: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'GT');
return Base.nop();
},
brsh: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LE');
return Base.nop();
},
bset: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.macro('SREG_SET_BIT (' + instr.parsed.opd[0] + ')', '#define SREG_SET_BIT(x) __asm(bset (x))');
},
call: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
//name, args, is_pointer, returns, bits
if (instr.parsed.opd[0].indexOf('0x') == 0) {
return Base.call(Variable.functionPointer(instr.parsed.opd[0], 16), []);
}
return Base.call(instr.parsed.opd[0], []);
},
cli: function(instr) {
instr.setBadJump();
return Base.macro('DISABLE_INTERRUPTS', '#define DISABLE_INTERRUPTS __asm(cli)');
},
clr: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], '0');
},
clt: function(instr) {
instr.setBadJump();
return Base.macro('CLEAR_TRANSFER_FLAG', '#define CLEAR_TRANSFER_FLAG __asm(clt)');
},
com: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.subtract(instr.parsed.opd[0], '0xff', instr.parsed.opd[0]);
},
cp: function(instr, context) {
instr.setBadJump();
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return Base.nop();
},
cpc: function(instr, context, instructions) {
instr.setBadJump();
var p = instructions.indexOf(instr);
if (instructions[p - 1] && instructions[p - 1].parsed.mnem.indexOf('cp') == 0) {
_compare_bytes(instr.parsed.opd[0], instr.parsed.opd[1], context);
} else {
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
}
context.cond.instr = instr;
return Base.nop();
},
cpi: function(instr, context) {
instr.setBadJump();
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return Base.nop();
},
dec: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
_compare('--' + instr.parsed.opd[0], '0', context);
context.cond.instr = instr;
return Base.decrease(instr.parsed.opd[0], '1');
},
eor: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.xor);
},
icall: function(instr, context) {
_returns_r0(instr, context);
instr.setBadJump();
//name, args, is_pointer, returns, bits
var op = Base.call(Variable.functionPointer(AVR_MEMORY.z.name), []);
Global().context.addMacro(AVR_MEMORY.z.macro);
return op;
},
ijmp: function(instr, context) {
_returns_r0(instr, context);
instr.setBadJump();
var op = Base.goto(AVR_MEMORY.z.name);
Global().context.addMacro(AVR_MEMORY.z.macro);
return op;
},
in: function(instr, context) {
_returns_r0(instr, context);
var e = instr.parsed.opd;
return Base.macro('READ_FROM_IO (' + e[1] + ', ' + e[0] + ')', '#define READ_FROM_IO(x,y) __asm(in (y), (x))');
},
inc: function(instr, context) {
_returns_r0(instr, context);
_compare('++' + instr.parsed.opd[0], '0', context);
context.cond.instr = instr;
return Base.increase(instr.parsed.opd[0], '1');
},
iret: function(instr) {
return Base.macro('RETURN_FROM_INTERRUPT', '#define RETURN_FROM_INTERRUPT __asm(iret)');
},
jmp: function(instr, context) {
return Base.nop();
},
ld: _load16,
ldd: function(instr, context) {
_returns_r0(instr, context);
var ptr = instr.parsed.opd[1].match(/([xyz]|[+-0-9]+)/g);
var offset = ptr[1].replace(/(-)/, ' - ').replace(/(\+)/, ' + ');
//pointer, register, bits, is_signed
var op = Base.read_memory(AVR_MEMORY[ptr[0]].name + offset, instr.parsed.opd[0], 8, false);
Global().context.addMacro(AVR_MEMORY[ptr[0]].macro);
return op;
},
ldi: function(instr, context) {
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], instr.parsed.opd[1]);
},
lds: function(instr, context) {
_returns_r0(instr, context);
//pointer, register, bits, is_signed
return Base.read_memory(instr.parsed.opd[1], instr.parsed.opd[0], 8, false);
},
lpm: _load16,
lsl: function(instr, context) {
_returns_r0(instr, context);
return Base.shift_left(instr.parsed.opd[0], instr.parsed.opd[0], '1');
},
lsr: function(instr, context) {
_returns_r0(instr, context);
return Base.shift_right(instr.parsed.opd[0], instr.parsed.opd[0], '1');
},
mov: function(instr, context) {
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], instr.parsed.opd[1]);
},
movw: function(instr, context) {
_returns_r0(instr, context);
var a1 = instr.parsed.opd[0];
var a2 = _next_register(instr.parsed.opd[0]);
var b1 = instr.parsed.opd[1];
var b2 = _next_register(instr.parsed.opd[1]);
var op1 = Base.assign(a1, b1);
var op2 = Base.assign(a2, b2);
return Base.composed([op1, op2]);
},
mul: function(instr, context) {
context.returns = 'r0';
var name = 'value' + (++AVR_CTR);
var ops = [];
ops.push(Base.multiply('uint16_t ' + name, instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.assign('r0', '(' + name + ' & 0xFF)'));
ops.push(Base.assign('r1', '(' + name + ' >> 8)'));
return Base.composed(ops);
},
muls: function(instr, context) {
context.returns = 'r0';
var name = 'value' + (++AVR_CTR);
var ops = [];
ops.push(Base.multiply('int16_t ' + name, instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.assign('r0', '(' + name + ' & 0xFF)'));
ops.push(Base.assign('r1', '(' + name + ' >> 8)'));
return Base.composed(ops);
},
mulsu: function(instr, context) {
context.returns = 'r0';
var name = 'value' + (++AVR_CTR);
var ops = [];
ops.push(Base.multiply('uint16_t ' + name, instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.assign('r0', '(' + name + ' & 0xFF)'));
ops.push(Base.assign('r1', '(' + name + ' >> 8)'));
return Base.composed(ops);
},
neg: function(instr, context) {
_returns_r0(instr, context);
return Base.negate(instr.parsed.opd[0], instr.parsed.opd[0]);
},
nop: function(instr) {
instr.setBadJump();
return Base.nop();
},
not: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.not(instr.parsed.opd[0], instr.parsed.opd[0]);
},
or: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.or);
},
ori: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.or);
},
out: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context, true);
var e = instr.parsed.opd;
return Base.macro('WRITE_TO_IO (' + e[0] + ', ' + e[1] + ')', '#define WRITE_TO_IO(x,y) __asm(in (x), (y))');
},
pop: function(instr, context) {
instr.setBadJump();
if (instr.parsed.opd[0] == 'r0') {
// if pops an r0, then the return value is void.
context.returns = null;
}
return Base.nop();
},
push: function(instr, context) {
instr.setBadJump();
return Base.nop();
},
rcall: function(instr, context) {
_returns_r0(instr, context);
return Base.call(Variable.functionPointer(instr.parsed.opd[0], AVR_MEM_BITS), []);
},
ret: function(instr, context) {
_returns_r0(instr, context);
// returns r1:r0
// but if pop r0 then return void.
return Base.return(context.returns);
},
reti: function(instr) {
return Base.macro('RETURN_FROM_INTERRUPT', '#define RETURN_FROM_INTERRUPT __asm(reti)');
},
rjmp: function(instr, context) {
_returns_r0(instr, context);
return Base.nop();
},
rol: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.rotate_left(instr.parsed.opd[0], instr.parsed.opd[0], '1', 8);
},
ror: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.rotate_right(instr.parsed.opd[0], instr.parsed.opd[0], '1', 8);
},
sbc: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.subtract);
},
sbci: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.subtract);
},
sbiw: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
var b = instr.parsed.opd[1];
var a1 = instr.parsed.opd[0];
var a2 = _next_register(instr.parsed.opd[0]);
_compare_values(a1, b, a2, b, context);
context.cond.instr = instr;
if (b == '0x00' || b == '0') {
return Base.nop();
}
var op1 = null;
var op2 = null;
if (b == '0x01' || b == '1') {
op1 = Base.decrease(a1, '1');
op2 = Base.decrease(a2, '1');
} else {
op1 = Base.subtract(a1, a1, b);
op2 = Base.subtract(a2, a2, b);
}
return Base.composed([op1, op2]);
},
sbr: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.or(instr.parsed.opd[0], instr.parsed.opd[1]);
},
sbrc: function(instr, context, instructions) {
instr.setBadJump();
var next = instructions[instructions.indexOf(instr) + 1];
if (next) {
_compare('(' + instr.parsed.opd[0] + ' & (1 << ' + instr.parsed.opd[1] + '))', '0', context);
context.cond.instr = instr;
_conditional_next(next, context, instructions, 'EQ');
return Base.or(instr.parsed.opd[0], instr.parsed.opd[1]);
}
return Base.nop();
},
sbrs: function(instr, context, instructions) {
instr.setBadJump();
var next = instructions[instructions.indexOf(instr) + 1];
if (next) {
_compare('(' + instr.parsed.opd[0] + ' & (1 << ' + instr.parsed.opd[1] + '))', '1', context);
context.cond.instr = instr;
_conditional_next(next, context, instructions, 'EQ');
return Base.or(instr.parsed.opd[0], instr.parsed.opd[1]);
}
return Base.nop();
},
sei: function(instr) {
instr.setBadJump();
return Base.macro('ENABLE_INTERRUPTS', '#define ENABLE_INTERRUPTS __asm(sei)');
},
ser: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], '0xff');
},
set: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.macro('SET_TRANSFER_FLAG', '#define SET_TRANSFER_FLAG __asm(set)');
},
st: _store16,
std: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
var ptr = instr.parsed.opd[0].match(/([xyz]|[+-0-9]+)/g);
var offset = ptr[1].replace(/(-)/, ' - ').replace(/(\+)/, ' + ');
//pointer, register, bits, is_signed
var op = Base.write_memory(AVR_MEMORY[ptr[0]].name + offset, instr.parsed.opd[1], 8, false);
Global().context.addMacro(AVR_MEMORY[ptr[0]].macro);
return op;
},
sts: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
//pointer, register, bits, is_signed
return Base.write_memory(instr.parsed.opd[0], instr.parsed.opd[1], 8, false);
},
sub: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.subtract);
},
subi: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
if (instr.parsed.opd[1] == '0x00' || instr.parsed.opd[1] == '0') {
instr.setBadJump();
return Base.nop();
}
return _common_math(instr, Base.subtract);
},
tst: function(instr, context) {
instr.setBadJump();
_compare(instr.parsed.opd[0], '0', context);
context.cond.instr = instr;
},
wdr: function(instr, context) {
instr.setBadJump();
return Base.macro('CLEAR_WATCHDOG', '#define CLEAR_WATCHDOG __asm(wdr)');
},
invalid: function(instr) {
instr.setBadJump();
return Base.nop();
}
},
parse: function(asm) {
asm = asm.toLowerCase();
var ret = asm.replace(/\[|\]/g, ' ').replace(/,/g, ' ');
ret = ret.replace(/\{|\}/g, ' ').replace(/\s+/g, ' ');
ret = ret.trim().replace(/0x00/, '0').split(' ');
return {
mnem: ret.shift(),
opd: ret
};
},
context: function() {
return {
cond: {
a: null,
b: null,
instr: null
},
returns: null
};
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return context.returns == null ? 'void' : 'uint8_t';
}
};
File diff suppressed because it is too large. Load diff
+427
View File
@@ -0,0 +1,427 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from '../core/base.js';
import Variable from '../core/variable.js';
var _to_size = function(value) {
if (value == 'b') {
return 8;
} else if (value == 'w') {
return 16;
} else if (value == 'l') {
return 32;
}
return 0;
};
var _as_pointer = function(e, where, signed, ispointer) {
var arg = e.opd[where];
if (arg.pointer) {
if (arg.presub) {
var m = e.bits / 8;
if (m == 1) {
arg = Variable.pointer('--' + arg.pointer, e.bits, signed);
} else {
arg = Variable.pointer(arg.pointer + ' -= ' + m, e.bits, signed);
}
} else {
return Variable.pointer(arg.pointer, e.bits, signed);
}
} else if (ispointer && arg.register.indexOf('0x') == 0) {
var tokens = arg.register.replace(/\.([bwl])/, ' $1').split(' ');
arg = Variable.pointer(tokens[0], _to_size(tokens[1]), signed);
} else {
return arg.register;
}
return arg;
};
var _is_register = function(name) {
return name && name.match(/\b[acdsACDS][0-9ixIX]\b/);
};
var _common_math = function(e, op) {
var src = _as_pointer(e, 0, true);
var dst = _as_pointer(e, 1, true);
if (e.opd[1].postadd) {
return Base.composed([op(dst, dst, src), Base.add(e.opd[1].register, e.opd[1].register, '' + (e.bits / 8))]);
}
return op(dst, dst, src);
};
var _move = function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = _as_pointer(e, 0, true, true);
var dst = _as_pointer(e, 1, true, true);
return Base.assign(dst, src);
};
var _move_multiple = function(instr, context) {
instr.setBadJump();
var memory, pointer, postadd, register, op;
var e = instr.parsed;
var incr = (e.bits / 8).toString();
var ops = [];
if (e.opd[0].pointer) {
//movem.l -(a7), d2-d3/a2-a5
memory = _as_pointer(e, 0, false);
pointer = e.opd[0].register;
postadd = e.opd[0].postadd;
register = e.opd[1].register;
op = Base.read_memory;
} else {
//movem.l d2-d3/a2-a5, -(a7)
memory = _as_pointer(e, 1, false);
pointer = e.opd[1].register;
postadd = e.opd[1].postadd;
register = e.opd[0].register;
op = Base.write_memory;
}
var reg = register.split('/');
for (var i = 0; i < reg.length; i++) {
var prefix = reg[i].charAt(0);
var tmp = reg[i].replace(/[a-zA-Z]/g, '').split('-');
var start = tmp[0];
var end = tmp[1] || tmp[0];
for (var j = start; j <= end; j++) {
ops.push(op(memory, prefix + j, e.bits, false));
if (postadd) {
ops.push(Base.add(pointer, pointer, incr));
}
}
}
return Base.composed(ops);
};
var _compare = function(instr, context) {
instr.setBadJump();
context.cond.a = _as_pointer(instr.parsed, 1, false);
context.cond.b = _as_pointer(instr.parsed, 0, false);
return Base.nop();
};
var _conditional = function(instr, context, type, zero) {
instr.conditional(context.cond.a, context.cond.b, type);
return Base.nop();
};
var _bitmask = function(offset, size) {
var mask = 0;
for (var i = 0; i < size; i++) {
mask <<= 1;
mask |= 1;
}
return '0x' + ((mask << offset) >>> 0).toString(16);
};
export default {
instructions: {
add: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.add);
},
addi: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.add);
},
addq: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.add);
},
and: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.and);
},
andi: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.and);
},
bftst: function(instr, context) {
instr.setBadJump();
var vals = instr.assembly.match(/(\w+)(?:{(\d+):(\d+)})/);
var mask = _bitmask(vals[2], vals[3]);
var test = Variable.local('(' + vals[1] + ' & ' + mask + ')');
context.cond.a = test;
context.cond.b = '0';
return Base.nop();
},
bne: function(instr, context) {
return _conditional(instr, context, 'NE');
},
beq: function(instr, context) {
return _conditional(instr, context, 'EQ');
},
bgt: function(instr, context) {
return _conditional(instr, context, 'GT');
},
bge: function(instr, context) {
return _conditional(instr, context, 'GE');
},
blt: function(instr, context) {
return _conditional(instr, context, 'LT');
},
ble: function(instr, context) {
return _conditional(instr, context, 'LE');
},
bra: function(instr, context) {
return Base.nop();
},
btst: function(instr, context) {
instr.setBadJump();
var and = instr.parsed.opd[0].register == '0x0' ? ' & 1)' : ' & (1 << ' + instr.parsed.opd[0].register + '))';
var test = Variable.local('(' + instr.parsed.opd[1].register + and);
context.cond.a = test;
context.cond.b = '0';
return Base.nop();
},
clr: function(instr, context) {
var e = instr.parsed;
var dst = _as_pointer(e, 0, false);
var op = Base.assign(dst, '0');
if (e.opd[0].postadd) {
var ptr_reg = e.opd[0].register;
return Base.composed([op, Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))]);
}
return op;
},
cmp: _compare,
cmpi: _compare,
eori: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.xor);
},
jsr: function(instr) {
var arg = _is_register(instr.parsed.opd[0].register) ? Variable.functionPointer(instr.parsed.opd[0].register) : instr.parsed.opd[0].register;
return Base.call(arg, []);
},
lea: function(instr, context) {
instr.setBadJump();
var src = instr.string ? Variable.string(instr.string) : _as_pointer(instr.parsed, 0, false, true);
var dst = _as_pointer(instr.parsed, 1, false, true);
return Base.assign(dst, src);
},
link: function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = e.opd[0].register;
var dst = e.opd[1].register;
return Base.write_memory(dst == '0x0' ? 'a7' : ('a7 + ' + dst), src, e.bits, false);
},
lsl: function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = _as_pointer(e, 0, false);
var dst = _as_pointer(e, 1, false);
if (!e.opd[1]) {
return Base.shift_left(dst, dst, '1');
} else if (e.opd[1].pointer) {
var op = Base.shift_left(dst, dst, src);
if (e.opd[1].postadd) {
var ptr_reg = e.opd[1].register;
return Base.composed([op, Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))]);
}
return op;
}
return Base.shift_left(dst, dst, src);
},
lsr: function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = _as_pointer(e, 0, false);
var dst = _as_pointer(e, 1, false);
if (!e.opd[1]) {
return Base.shift_right(dst, dst, '1');
} else if (e.opd[1].pointer) {
var op = Base.shift_right(dst, dst, src);
if (e.opd[1].postadd) {
var ptr_reg = e.opd[1].register;
return Base.composed([op, Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))]);
}
return op;
}
return Base.shift_right(dst, dst, src);
},
move: function(instr) {
instr.setBadJump();
var ptr_reg, ops;
var e = instr.parsed;
var pointer = _as_pointer(e, 0, false, true);
var register = _as_pointer(e, 1, false, true);
if (e.opd[1].postadd) {
ptr_reg = e.opd[1].register;
ops = [
Base.read_memory(pointer, register, e.bits, false),
Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))
];
if (e.opd[0].postadd) {
ptr_reg = e.opd[0].register;
ops.push(Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8)));
}
return Base.composed(ops);
} else if (e.opd[0].postadd) {
ptr_reg = e.opd[0].register;
ops = [
Base.read_memory(pointer, register, e.bits, false),
Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))
];
return Base.composed(ops);
}
return Base.read_memory(pointer, register, e.bits, false);
},
movea: _move,
movem: _move_multiple,
moveq: function(instr, context) {
instr.setBadJump();
return Base.assign(instr.parsed.opd[1].register, instr.parsed.opd[0].register);
},
or: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.or);
},
ori: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.or);
},
pea: function(instr) {
instr.setBadJump();
var bits = instr.parsed.bits;
var pointer = Variable.pointer('a7 -= 4', bits, false);
var register = instr.string ? Variable.string(instr.string) : _as_pointer(instr.parsed, 0, false);
return Base.write_memory(pointer, register, bits, false);
},
rts: function(instr) {
instr.setBadJump();
return Base.return();
},
sf: function(instr, context) {
instr.setBadJump();
var e = instr.parsed;
var dst = _as_pointer(e, 0, false, true);
var op = Base.assign(dst, '0');
if (e.opd[1].postadd) {
return Base.composed([op, Base.add(e.opd[1].register, e.opd[1].register, '' + (e.bits / 8))]);
}
return op;
},
st: function(instr, context) {
instr.setBadJump();
var e = instr.parsed;
var dst = _as_pointer(e, 0, false, true);
var op = Base.assign(dst, '1');
if (e.opd[0].postadd) {
return Base.composed([op, Base.add(e.opd[0].register, e.opd[0].register, '' + (e.bits / 8))]);
}
return op;
},
sub: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.subtract);
},
subq: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.subtract);
},
tst: function(instr, context) {
instr.setBadJump();
context.cond.a = _as_pointer(instr.parsed, 0, false);
context.cond.b = '0';
return Base.nop();
},
unlk: function(instr) {
instr.setBadJump();
var e = instr.parsed;
return Base.read_memory(e.opd[1].register || 'a7', e.opd[0].register, e.bits, false);
},
invalid: function(instr) {
instr.setBadJump();
return Base.nop();
}
},
parse: function(asm) {
const expr = /([a-zA-Z]+)(\.[bwl])?\s+([\w.:_-]+\([\w. *,[\]]+\)|-?\([\w. *,[\]]+\)\+?|[\w./:_-]+)(?:,\s+([\w.:_-]+\([\w. *,[\]]+\)|-?\([\w. *,[\]]+\)\+?|[\w./:_-]+))?/;
var token = asm.match(expr);
token.shift();
/*
* [
"move.l obj.__unctrl(d0.l * 4), -(a7)",
"move",
".l",
"obj.__unctrl(d0.l * 4)",
"-(a7)"
* ]
* token[0] = assembly
* token[1] = mnem
* token[2] = bits
* token[3] = opd0
* token[4] = opd1
*/
var mnem = token.shift();
var bits = token.shift();
var ret = {
mnem: mnem,
bits: _to_size(bits ? bits.substring(1) : 'l'),
opd: token.filter(function(x) {
return x ? true : false;
}).map(function(x) {
var d = {
presub: false,
postadd: false,
pointer: null,
register: null,
};
var isreg = x.indexOf('(') < 0;
var ptr = x.replace(/([\w.:_-][\w.:_-]+)\(/, '$1 + ').replace(/(-?\()|\)\+?/g, ' ').replace(/,\sinvalid\.[bwl]/, '');
var p = x.replace(/[(),]/g, ' ').replace(/\s+/g, ' ');
p = p.replace(/invalid\.[bwl]/, '');
p = p.trim().split(' ');
if (p[0] == '-') {
d.presub = true;
p.shift();
} else if (p[p.length - 1] == '+') {
d.postadd = true;
p.pop();
}
if (isreg) {
d.register = p.pop();
} else if (ptr.indexOf('-') > 0 || ptr.indexOf('+') > 0 || ptr.indexOf('*') > 0) {
d.pointer = ptr.replace(/(\d)\.[bwl]/, '$1').replace(/,/g, ' +').trim();
d.register = ptr.match(/[ad]\d+/)[0];
} else {
d.pointer = p.join(' + ');
d.register = p[0];
}
return d;
}),
};
return ret;
},
context: function() {
return {
cond: {
a: '?',
b: '?'
},
leave: false,
vars: []
};
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
+10 -13
View File
@@ -1,12 +1,10 @@
// SPDX-FileCopyrightText: 2017-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
var Instruction = require('libdec/core/instruction');
var Base = require('libdec/core/base');
var Variable = require('libdec/core/variable');
var Long = require('libdec/long');
import Instruction from '../core/instruction.js';
import Base from '../core/base.js';
import Variable from '../core/variable.js';
import Long from '../long.js';
const _mips_registers = [
'zero', 'at', 'v0', 'v1',
@@ -138,10 +136,10 @@
];
var address = [
function(e, addr) {
return Long.fromString(_hex(e.opd[1]) + '0000', true, 16);
return Long.from(_hex(e.opd[1]) + '0000', true, 16);
},
function(e, addr) {
var n = Long.fromString(_hex(e.opd[2]), e.mnem.indexOf('u') > 0, 16);
var n = Long.from(_hex(e.opd[2]), e.mnem.indexOf('u') > 0, 16);
var op = e.mnem.replace(/[iu]/g, '');
return addr[op](n);
},
@@ -164,8 +162,8 @@
}
--i;
if (instr.parsed.opd[0] != 'gp') {
instr.string = Global.xrefs.find_string(addr);
instr.symbol = Global.xrefs.find_symbol(addr);
instr.string = Global().xrefs.find_string(addr);
instr.symbol = Global().xrefs.find_symbol(addr);
addr = instr.string ? Variable.string(instr.string) : (instr.symbol || ('0x' + addr.toString(16)).replace(/0x-/, '-0x'));
instr.valid = true;
} else {
@@ -219,7 +217,7 @@
'bgtz', 'bgez', 'beq', 'bne', 'bnel'
];
return {
export default {
instructions: {
'nop': function(instr) {
return Base.nop();
@@ -523,4 +521,3 @@
return 'void';
}
};
});
File diff suppressed because it is too large. Load diff
+585
View File
@@ -0,0 +1,585 @@
// SPDX-FileCopyrightText: 2021-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from '../core/base.js';
import Variable from '../core/variable.js';
import Long from '../long.js';
function load_bits(instr, bits, unsigned) {
instr.setBadJump();
var e = instr.parsed;
var arg = e.opd[1].replace(/\)/, '').split('(');
if (arg[0].indexOf('-sym.') == 0 && arg[1] == 'gp') {
return Base.assign(e.opd[0], arg[0].replace(/^-/, ''));
} else if (arg[1] == '0') {
//pointer, register, bits, is_signed
return Base.read_memory(arg[0], e.opd[0], bits, !unsigned);
} else if (arg[0] == '0') {
//pointer, register, bits, is_signed
return Base.read_memory(arg[1], e.opd[0], bits, !unsigned);
}
arg[0] = arg[0].length > 0 ? parseInt(arg[0]) : NaN;
if (!isNaN(arg[0])) {
if (arg[0] < 0) {
arg[0] = " - 0x" + Math.abs(arg[0]).toString(16);
} else {
arg[0] = " + 0x" + arg[0].toString(16);
}
return Base.read_memory(arg[1] + arg[0], e.opd[0], bits, !unsigned);
}
return Base.read_memory(arg[1], e.opd[0], bits, !unsigned);
}
function store_bits(instr, bits, unsigned) {
instr.setBadJump();
var e = instr.parsed;
var arg = e.opd[1].replace(/\)/, '').split('(');
if (arg[1] == '0') {
//pointer, register, bits, is_signed
return Base.write_memory(arg[0], e.opd[0], bits, !unsigned);
} else if (arg[0] == '0') {
//pointer, register, bits, is_signed
return Base.write_memory(arg[1], e.opd[0], bits, !unsigned);
}
arg[0] = arg[0].length > 0 ? parseInt(arg[0]) : NaN;
if (!isNaN(arg[0])) {
if (arg[0] < 0) {
arg[0] = " - 0x" + Math.abs(arg[0]).toString(16);
} else {
arg[0] = " + 0x" + arg[0].toString(16);
}
return Base.write_memory(arg[1] + arg[0], e.opd[0], bits, !unsigned);
}
return Base.write_memory(arg[1], e.opd[0], bits, !unsigned);
}
function _csr_assign_3arg(instr) {
instr.setBadJump();
var dst = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
return Base.assign(dst, src);
}
function _generic_assign(instr) {
instr.setBadJump();
var dst = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
return Base.assign(dst, src);
}
function _generic_add(instr) {
instr.setBadJump();
var dst = instr.parsed.opd[0];
var src0 = instr.parsed.opd[1];
var src1 = instr.parsed.opd[2];
return Base.add(dst, src0, src1);
}
function op_bits3(instr, op) {
instr.setBadJump();
var dst = instr.parsed.opd[0];
var src0 = instr.parsed.opd[1];
var src1 = instr.parsed.opd[2];
return op(dst, src0, src1);
}
function assign_call(instr, name) {
var dst = instr.parsed.opd[0];
var args = instr.parsed.opd.slice(1);
return Base.special(dst + ' = ' + name + '( ', args.join(', ') + ')');
}
function _compare(instr, context, instructions, cmp, zero) {
instr.conditional(instr.parsed.opd[0], zero ? "0" : instr.parsed.opd[1], cmp);
var arg = instr.parsed.opd[instr.parsed.opd.length - 1];
if (arg.indexOf('0x') == 0) {
instr.jump = Long.from(arg, true);
}
return Base.nop();
}
function _is_last_instruction(instr, instructions) {
return instructions.indexOf(instr) == (instructions.length - 1);
}
function _hex(value) {
return parseInt(value).toString(16);
}
function lui32(instr, start, instructions, context) {
var addr = null;
var check = [
function(e, r) {
return e.mnem == 'lui' && e.opd[0] == r;
},
function(e, r) {
if (e.mnem == 'nop') {
return true;
}
return (e.mnem == 'ori' && (e.opd[0] == r || e.opd[0].indexOf('a') == 0) && e.opd[1] == r) ||
(e.mnem == 'addi' && (e.opd[0] == r || e.opd[0].indexOf('a') == 0) && e.opd[1] == r) ||
(e.mnem == 'addiu' && (e.opd[0] == r || e.opd[0].indexOf('a') == 0) && e.opd[1] == r);
},
];
var address = [
function(e, addr) {
var imm32 = instr.parsed.opd[1] << 12;
return Long.from(imm32, true);
},
function(e, addr) {
var n = Long.from(_hex(e.opd[2]), e.mnem.indexOf('u') > 0, 16);
var op = e.mnem.replace(/[iu]/g, '');
return addr[op](n);
},
];
var step = 0;
var i;
for (i = start; i < instructions.length && step < check.length; ++i) {
var elem = instructions[i].parsed;
if (!check[step](elem, instr.parsed.opd[0])) {
break;
}
addr = address[step](elem, addr);
step++;
if (instr.parsed.opd[0] == instructions[i].parsed.opd[0]) {
instructions[i].valid = false;
} else {
instr.valid = true;
instr = instructions[i];
}
}
--i;
if (instr.parsed.opd[0] != 'gp') {
instr.string = Global().xrefs.find_string(addr);
instr.symbol = Global().xrefs.find_symbol(addr);
addr = instr.string ? Variable.string(instr.string) : (instr.symbol || ('0x' + addr.toString(16)).replace(/0x-/, '-0x'));
instr.valid = true;
} else {
addr = ('0x' + addr.toString(16)).replace(/0x-/, '-0x');
instr.valid = false;
}
instr.code = Base.assign(instr.parsed.opd[0], addr);
return i;
}
export default {
instructions: {
auipc: function(instr) {
var dst = instr.parsed.opd[0];
var imm32 = parseInt(instr.parsed.opd[1]);
var src = instr.location.add(imm32);
return Base.assign(dst, '0x' + src.toString(16));
},
lui: function(instr) {
var dst = instr.parsed.opd[0];
var imm20 = instr.parsed.opd[1] << 12;
return Base.assign(dst, '0x' + imm20.toString(16));
},
lb: function(instr) {
return load_bits(instr, 8, false);
},
lh: function(instr) {
return load_bits(instr, 16, false);
},
lw: function(instr) {
return load_bits(instr, 32, false);
},
lwu: function(instr) {
return load_bits(instr, 32, true);
},
ld: function(instr) {
return load_bits(instr, 64, false);
},
lbu: function(instr) {
return load_bits(instr, 8, true);
},
lhu: function(instr) {
return load_bits(instr, 16, true);
},
'lr.w': function(instr) {
return load_bits(instr, 32, false);
},
'lr.d': function(instr) {
return load_bits(instr, 64, false);
},
sb: function(instr) {
return store_bits(instr, 8, false);
},
sh: function(instr) {
return store_bits(instr, 16, false);
},
sw: function(instr) {
return store_bits(instr, 32, false);
},
sd: function(instr) {
return store_bits(instr, 64, false);
},
'sc.w': function(instr) {
return store_bits(instr, 32, false);
},
'sc.d': function(instr) {
return store_bits(instr, 64, false);
},
'sext.w': function(instr) {
return Base.extend(instr.parsed.opd[0], instr.parsed.opd[1], 32);
},
add: _generic_add,
addi: _generic_add,
addw: _generic_add,
addiw: _generic_add,
and: function(instr) {
return op_bits3(instr, Base.and);
},
andi: function(instr) {
return op_bits3(instr, Base.and);
},
sub: function(instr) {
return op_bits3(instr, Base.subtract);
},
subw: function(instr) {
return op_bits3(instr, Base.subtract);
},
mul: function(instr) {
return op_bits3(instr, Base.multiply);
},
mulh: function(instr) {
return op_bits3(instr, Base.multiply);
},
mulw: function(instr) {
return op_bits3(instr, Base.multiply);
},
srli: function(instr) {
return op_bits3(instr, Base.shift_right);
},
srai: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sll: function(instr) {
return op_bits3(instr, Base.shift_left);
},
slli: function(instr) {
return op_bits3(instr, Base.shift_left);
},
srlw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
srliw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sraw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sraiw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sllw: function(instr) {
return op_bits3(instr, Base.shift_left);
},
slliw: function(instr) {
return op_bits3(instr, Base.shift_left);
},
div: function(instr) {
return op_bits3(instr, Base.divide);
},
divu: function(instr) {
return op_bits3(instr, Base.divide);
},
rem: function(instr) {
return op_bits3(instr, Base.module);
},
remu: function(instr) {
return op_bits3(instr, Base.module);
},
divw: function(instr) {
return op_bits3(instr, Base.divide);
},
divuw: function(instr) {
return op_bits3(instr, Base.divide);
},
remw: function(instr) {
return op_bits3(instr, Base.module);
},
remuw: function(instr) {
return op_bits3(instr, Base.module);
},
or: function(instr) {
return op_bits3(instr, Base.or);
},
ori: function(instr) {
return op_bits3(instr, Base.or);
},
xor: function(instr) {
return op_bits3(instr, Base.xor);
},
xori: function(instr) {
return op_bits3(instr, Base.xor);
},
'slt': function(instr) {
var e = instr.parsed;
return Base.conditional_assign(e.opd[0], e.opd[1], e.opd[2], 'LT', '1', '0');
},
'slti': function(instr) {
var e = instr.parsed;
return Base.conditional_assign(e.opd[0], e.opd[1], e.opd[2], 'LT', '1', '0');
},
'sltiu': function(instr) {
var e = instr.parsed;
var arg0 = Variable.local(e.opd[1], 32);
var arg1 = Variable.local(e.opd[2], 32);
return Base.conditional_assign(e.opd[0], arg0, arg1, 'LT', '1', '0');
},
'sltu': function(instr) {
var e = instr.parsed;
if (e.opd[2] == 'zero') {
e.opd[2] = '0';
}
var arg0 = Variable.local(e.opd[1], 32);
var arg1 = Variable.local(e.opd[2], 32);
return Base.conditional_assign(e.opd[0], arg0, arg1, 'LT', '1', '0');
},
'amoadd.w': _generic_add,
'amoor.w': function(instr) {
return op_bits3(instr, Base.or);
},
'amoxor.w': function(instr) {
return op_bits3(instr, Base.xor);
},
'amoand.w': function(instr) {
return op_bits3(instr, Base.and);
},
'amomin.w': function(instr) {
return assign_call(instr, 'min');
},
'amominu.w': function(instr) {
return assign_call(instr, 'min');
},
'amomax.w': function(instr) {
return assign_call(instr, 'max');
},
'amomaxu.w': function(instr) {
return assign_call(instr, 'max');
},
'amoadd.d': _generic_add,
'amoor.d': function(instr) {
return op_bits3(instr, Base.or);
},
'amoxor.d': function(instr) {
return op_bits3(instr, Base.xor);
},
'amoand.d': function(instr) {
return op_bits3(instr, Base.and);
},
'amomin.d': function(instr) {
return assign_call(instr, 'min');
},
'amominu.d': function(instr) {
return assign_call(instr, 'min');
},
'amomax.d': function(instr) {
return assign_call(instr, 'max');
},
'amomaxu.d': function(instr) {
return assign_call(instr, 'max');
},
mv: _generic_assign,
li: _generic_assign,
csrr: _generic_assign,
csrw: _generic_assign,
csrc: _generic_assign,
csrs: _generic_assign,
csrri: _generic_assign,
csrwi: _generic_assign,
csrci: _generic_assign,
csrsi: _generic_assign,
csrrwi: _csr_assign_3arg,
csrrci: _csr_assign_3arg,
csrrsi: _csr_assign_3arg,
beqz: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'EQ', true);
},
bnez: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'NE', true);
},
bltz: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LT', true);
},
blez: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LE', true);
},
bgtz: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GT', true);
},
bgez: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GE', true);
},
beq: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'EQ', false);
},
bne: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'NE', false);
},
blt: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LT', false);
},
ble: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LE', false);
},
bgt: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GT', false);
},
bge: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GE', false);
},
bltu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LT', false);
},
bleu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LE', false);
},
bgtu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GT', false);
},
bgeu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GE', false);
},
jal: function(instr, context, instructions) {
var fcn_name = instr.parsed.opd[1].replace(/\./g, '_');
if (fcn_name.indexOf('0x') == 0) {
fcn_name = fcn_name.replace(/0x/, 'fcn_');
}
var args = [];
var regs = ['a7', 'a6', 'a5', 'a4', 'a3', 'a2', 'a1', 'a0'];
var found = 0,
i;
for (i = instructions.indexOf(instr) - 1; i >= 0; i--) {
if (instructions[i].parsed.mnem.startsWith('b') ||
instructions[i].parsed.mnem.startsWith('j')) {
break;
}
var reg = instructions[i].parsed.opd[0];
if (regs.indexOf(reg) >= 0) {
found = parseInt(reg.substr(1, 3)) + 1;
break;
}
}
for (i = 0; i < found; i++) {
args.push('a' + i);
}
return Base.call(fcn_name, args);
},
jalr: function(instr) {
var is_return = false;
var arg = instr.parsed.opd[0];
if (arg.indexOf('(') > 0) {
arg = arg.replace(/\(|\)/g, ' ').trim().split(' ');
if (arg[1] == 'ra') {
is_return = true;
}
arg = arg[1] + ' + ' + arg[0];
arg = arg.replace(/\+ -/, '-');
}
if (is_return || arg == 'ra') {
if (is_return) {
instr.comments.push('return address: ' + arg);
}
return Base.return(instr.parsed.opd[1]);
}
return Base.call(arg, [], true);
},
j: function(instr, context, instructions) {
var arg = instr.parsed.opd[0];
if (arg.indexOf('0x') == 0) {
instr.jump = Long.from(arg);
} else if (_is_last_instruction(instr, instructions)) {
return Base.call(arg, []);
}
return Base.nop();
},
ret: function(instr) {
return Base.return();
},
uret: function(instr) {
return Base.return();
},
sret: function(instr) {
return Base.return();
},
mret: function(instr) {
return Base.return();
},
fence: function() {
return Base.macro('memory_fence()', '#define memory_fence() __asm(fence)');
},
'fence.i': function() {
return Base.macro('memory_fence_i()', '#define memory_fence_i() __asm(fence.i)');
},
'sfence.vma': function() {
return Base.macro('memory_sfence_vma()', '#define memory_sfence_vma() __asm(sfence.vma)');
},
ebreak: function() {
return Base.macro('environment_break()', '#define environment_break() __asm(ebreak)');
},
ecall: function() {
return Base.macro('environment_call()', '#define environment_call() __asm(ecall)');
},
wfi: function() {
return Base.macro('wait_for_interrupt()', '#define wait_for_interrupt() __asm(wfi)');
},
nop: function(instr) {
return Base.nop();
},
invalid: function() {
return Base.nop();
}
},
parse: function(asm) {
asm = asm.replace(/,/g, ' ').replace(/\s+/g, ' ').trim().split(' ').map(function(x) {
if (x == 'zero') {
return '0';
}
return x;
});
var mnem = asm.shift();
if (mnem.indexOf('amo') == 0) {
// atomic ops.
asm = asm.map(function(x) {
return x.replace(/\(|\)/g, '');
});
}
return {
mnem: mnem,
opd: asm
};
},
context: function() {
return {
cond: {
a: null,
b: null
}
};
},
preanalisys: function(instructions) {},
postanalisys: function(instructions, context) {
/* simplifies any load address 32/64 bit */
for (var i = 0; i < instructions.length; i++) {
if (instructions[i].parsed.mnem == 'lui') {
i = lui32(instructions[i], i, instructions);
}
}
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
+555
View File
@@ -0,0 +1,555 @@
// SPDX-FileCopyrightText: 2019-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
// https://www.rockbox.org/wiki/pub/Main/DataSheets/sh1_2p.pdf
// http://www.shared-ptr.com/sh_insns.html
import Instruction from '../core/instruction.js';
import Base from '../core/base.js';
import Variable from '../core/variable.js';
const _s = 's';
const _carry = 'c';
const _mac = 'mac';
const _size_map = {
"b": 8,
"w": 16,
"l": 32
};
const _compare_map = {
'eq': 'EQ',
'hi': 'GT',
'hs': 'GE',
'ge': 'GE',
'gt': 'GT',
'pl': 'GT',
'pz': 'GE',
'str': 'str',
};
const _reverse_map = {
'EQ': 'NE',
'GT': 'LE',
'GE': 'LT',
};
const _branch_list = [
'bra',
'braf',
'bsr',
'bsrf',
'jmp',
'jsr',
'rte',
'rts'
];
function _set_conditional(instr, context, cmp, invert) {
if (invert) {
cmp = _reverse_map[cmp];
}
instr.conditional(context.cond.a, context.cond.b, cmp);
return Base.nop();
}
function _require_composed(instr, idx) {
var e = instr.parsed;
return e.opd[idx].increment || e.opd[idx].decrement;
}
function _handle_pointer(instr, idx, ops) {
var e = instr.parsed;
var size = e.size || 32;
if (e.opd[idx].increment) {
ops.push(Base.increase(e.opd[idx].token, size / 8));
} else if (e.opd[idx].decrement) {
ops.unshift(Base.decrease(e.opd[idx].token, size / 8));
}
}
function _arg(instr, idx) {
var e = instr.parsed;
if (e.opd[idx].pointer) {
// a great way to fix PC + N
if (e.opd[idx].token.startsWith('pc +')) {
var n = parseInt(e.opd[idx].token.substr('pc +'.length));
var p = instr.location.add(n);
e.opd[idx].token = '0x' + p.toString(16);
}
return Variable.pointer(e.opd[idx].toString(), e.size || 32, true);
}
return e.opd[idx].toString();
}
function _op_move(instr) {
var ops = [];
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
if (instr.parsed.size) {
ops.push(Base.cast(dst, src, 'int' + instr.parsed.size + '_t'));
} else {
ops.push(Base.assign(dst, src));
}
if (_require_composed(instr, 0) || _require_composed(instr, 1)) {
if (_require_composed(instr, 0)) {
_handle_pointer(instr, 0, ops);
} else {
_handle_pointer(instr, 1, ops);
}
return Base.composed(ops);
}
return ops[0];
}
var _is_last_instruction = function(instr, instructions) {
return instructions.indexOf(instr) == (instructions.length - 1);
};
export default {
instructions: {
mov: _op_move,
mova: _op_move,
movt: function(instr, context, instructions) {
instr.parsed.opd[0].token = _carry;
return _op_move(instr);
},
swap: function(instr, context, instructions) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.swap(dst, src, 32);
},
/*
xtrct: function(instr, context, instructions) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.?????(dst, src);
},
*/
add: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.add(dst, dst, src);
},
addc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.add(dst, dst, src + ' + ' + _carry);
},
addv: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
instr.comments.push('if overflows, then ' + _carry + ' = 1.');
return Base.add(dst, dst, src + ' + ' + _carry);
},
cmp: function(instr, context) {
var a = _arg(instr, 0);
var b = _arg(instr, 1);
if (instr.parsed.cmp != 'str') {
context.cond.a = a;
context.cond.b = b;
context.cond.cmp = instr.parsed.cmp;
} else {
context.cond.a = (a === b) ? a : '(' + a + ' & ' + b + ')';
context.cond.b = '0';
context.cond.cmp = 'EQ';
}
},
tst: function(instr, context) {
var a = _arg(instr, 0);
var b = _arg(instr, 1);
context.cond.a = (a === b) ? a : '(' + a + ' & ' + b + ')';
context.cond.b = '0';
context.cond.cmp = 'EQ';
},
div1: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.divide(dst, dst, src);
},
dmuls: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(dst, dst, src);
},
dt: function(instr) {
var dst = _arg(instr, 1);
return Base.decrease(dst, dst, 1);
},
exts: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'int' + instr.parsed.size + '_t');
},
extu: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'uint' + instr.parsed.size + '_t');
},
mul: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(_mac, dst, src);
},
muls: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(_mac, dst, src);
},
mulu: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(_mac, dst, src);
},
neg: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.negate(dst, src);
},
negc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.composed([
Base.negate(dst, src),
Base.subtract(dst, dst, _carry),
]);
},
sub: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.subtract(dst, dst, src);
},
subc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.composed([
Base.subtract(dst, dst, src),
Base.subtract(dst, dst, _carry),
]);
},
subv: function(instr) {
instr.comments.push('if underflows, then ' + _carry + ' = 1.');
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.subtract(dst, dst, src);
},
and: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.and(dst, dst, src);
},
not: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.not(dst, src);
},
or: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.or(dst, dst, src);
},
xor: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.xor(dst, dst, src);
},
rotl: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_left(src, src, 1, 32);
},
rotr: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_right(src, src, 1, 32);
},
rotcl: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_left(src, src, 1, 32);
},
rotcr: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_right(src, src, 1, 32);
},
shal: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 1);
},
shar: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 1);
},
shll: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 1);
},
shlr: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 1);
},
shll2: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 2);
},
shlr2: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 2);
},
shll8: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 8);
},
shlr8: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 8);
},
shll16: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 16);
},
shlr16: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 16);
},
ldc: _op_move,
lds: _op_move,
stc: _op_move,
sts: _op_move,
clrt: function(instr) {
return Base.assign(_carry, '0');
},
clrs: function(instr) {
return Base.assign(_s, '0');
},
sett: function(instr) {
return Base.assign(_carry, '1');
},
sets: function(instr) {
return Base.assign(_s, '1');
},
fmov: _op_move,
flds: _op_move,
fsts: _op_move,
fldi0: function(instr) {
var src = _arg(instr, 1);
return Base.assign(src, '0.0');
},
fldi1: function(instr) {
var src = _arg(instr, 1);
return Base.assign(src, '1.0');
},
fabs: function(instr) {
var src = _arg(instr, 1);
return Base.and(src, src, '0x7FFFFFFF');
},
fneg: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.negate(dst, src);
},
fadd: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.add(dst, dst, src);
},
fsub: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.subtract(dst, dst, src);
},
fmul: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(dst, dst, src);
},
fdiv: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.divide(dst, dst, src);
},
fsqrt: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.assign(dst, Base.call('sqrt', [src]));
},
fcmp: function(instr, context) {
var a = _arg(instr, 0);
var b = _arg(instr, 1);
context.cond.a = a;
context.cond.b = b;
context.cond.cmp = instr.parsed.cmp;
},
float: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'float');
},
ftrc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'int32_t');
},
fsrra: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.special(dst + ' = 1.0 / sqrt (' + src + ')');
},
fsca: function(instr) {
var dst1 = _arg(instr, 0);
var dst2 = 'fr' + (parseInt(dst1.substr(2)) + 1).toString(16);
var src = _arg(instr, 1);
return Base.composed([
Base.assign(dst1, Base.call('sin', [src])),
Base.assign(dst2, Base.call('cos', [src]))
]);
},
bt: function(instr, context, instructions) {
return _set_conditional(instr, context, 'EQ');
},
bf: function(instr, context, instructions) {
return _set_conditional(instr, context, 'NE');
},
jsr: function(instr, context, instructions) {
var e = instr.parsed.opd;
return Base.call(Variable.functionPointer(e[1].token), []);
},
bsr: function(instr, context, instructions) {
var e = instr.parsed.opd;
if (_is_last_instruction(instr, instructions)) {
return Base.call(Variable.functionPointer(e[1].token), []);
}
return Base.nop();
},
bra: function(instr) {
var callname = _arg(instr, 1);
if (callname.startsWith('0x')) {
callname = Variable.functionPointer(callname);
}
return Base.call(callname, []);
},
braf: function(instr) {
var src = _arg(instr, 1);
return Base.call(Variable.functionPointer(src), []);
},
rte: function() {
return Base.return();
},
rts: function() {
return Base.return();
},
nop: function() {
return Base.nop();
},
invalid: function(instr, context, instructions) {
return Base.nop();
}
},
parse: function(assembly) {
assembly = assembly.trim().toLowerCase();
assembly = assembly.replace(/,/g, ' ');
assembly = assembly.replace(/\s+/g, ' ');
/*
Regex explaination:
^
(\w+)
\.?
([wlb])? // word/long/byte
([sn])? // delayed branch
\/?
(hi|eq|hs|pl|pz|str)? // compare flags
? // space might not exists (aka no 1st and 2nd param)
(
(
(@)? // Indirect or Direct access
(
(\(\w+\s\w+\)) A + B value
|
(-)? Pre-decrement
([\w._]+) register
(\+)? Post-increment
)
)
)?
? // space might not exists (aka no 2nd param)
(
(
(@)? // Indirect or Direct access
(
(\(\w+\s\w+\)) A + B value
|
(-)? Pre-decrement
([\w._]+) register
(\+)? Post-increment
)
)
)?
$
*/
var tokens = assembly.match(/^(\w+)\.?([wlb])?([sn])?\/?(hi|eq|hs|pl|pz|str)? ?(((@)?((\(\w+\s\w+\))|(-)?([\w._]+)(\+)?)))? ?(((@)?((\(\w+\s\w+\))|(-)?([\w._]+)(\+)?)))?$/);
var mnem = tokens[1];
var size = _size_map[tokens[2]];
var delayed = tokens[3] == 's';
var cmp = _compare_map[tokens[4]];
var opd = [{
pointer: tokens[7] == '@',
decrement: tokens[10] == '-',
increment: tokens[12] == '+',
token: tokens[11] || (tokens[9] ? tokens[9].replace(/\((\w+)\s(\w+)\)/g, '$2 + $1') : null),
toString: function() {
return this.token || '(null)';
}
}, {
pointer: tokens[15] == '@',
decrement: tokens[18] == '-',
increment: tokens[20] == '+',
token: tokens[19] || (tokens[17] ? tokens[17].replace(/\((\w+)\s(\w+)\)/g, '$2 + $1') : null),
toString: function() {
return this.token || '(null)';
}
}];
return {
mnem: mnem,
delayed: delayed,
cmp: cmp,
size: size,
opd: opd.reverse()
};
},
context: function() {
return {
cond: {
cmp: null,
a: '?',
b: '?'
}
};
},
preanalisys: function(instructions, context) {
/* delayed branch fix */
for (var i = 0; i < (instructions.length - 1); i++) {
var op = instructions[i].parsed.mnem;
if (_branch_list.indexOf(op) >= 0 && instructions[i + 1].parsed.mnem != 'nop') {
Instruction.swap(instructions, i, i + 1);
++i;
} else if (instructions[i].parsed.delayed && instructions[i + 1].parsed.mnem != 'nop') {
Instruction.swap(instructions, i, i + 1);
++i;
}
}
},
postanalisys: function(instructions, context) {},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
+395
View File
@@ -0,0 +1,395 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Instruction from '../core/instruction.js';
import Base from '../core/base.js';
import Variable from '../core/variable.js';
import Long from '../long.js';
var _call_fix_name = function(name) {
if (typeof name != 'string') {
return name;
}
if (name.indexOf('fcn.') == 0 || name.indexOf('func.') == 0) {
return name.replace(/[.:]/g, '_').replace(/__+/g, '_');
}
return name.replace(/\[reloc\.|\]/g, '').replace(/[.:]/g, '_').replace(/__+/g, '_').replace(/_[0-9a-f]+$/, '').replace(/^_+/, '');
};
var _load = function(instr, context, instruction, signed, bits) {
var e = instr.parsed;
if (e.opd[0].indexOf('+') > 0) {
var arg = e.opd[0].split('+');
var ops = [];
var value = Variable.uniqueName('local');
if (arg[1].indexOf('-') < 0) {
ops.push(Base.add(value, arg[0], arg[1]));
} else {
ops.push(Base.subtract(value, arg[0], arg[1].replace(/-/, '')));
}
ops.push(Base.read_memory(value, e.opd[1], bits, signed));
return Base.composed(ops);
}
//pointer, register, bits, is_signed
return Base.read_memory(e.opd[0], e.opd[1], bits, signed);
};
var _store = function(instr, context, instruction, signed, bits) {
var e = instr.parsed;
if (e.opd[1].indexOf('+') > 0) {
var arg = e.opd[1].split('+');
var ops = [];
var value = Variable.uniqueName('local');
if (arg[1].indexOf('-') < 0) {
ops.push(Base.add(value, arg[0], arg[1]));
} else {
ops.push(Base.subtract(value, arg[0], arg[1].replace(/-/, '')));
}
ops.push(Base.write_memory(value, e.opd[0], bits, signed));
return Base.composed(ops);
}
//pointer, register, bits, is_signed
return Base.write_memory(e.opd[1], e.opd[0], bits, signed);
};
var _conditional = function(instr, context, type) {
instr.conditional(context.cond.a, context.cond.b, type);
return Base.nop();
};
var _compare = function(instr, context, instructions) {
context.cond.a = instr.parsed.opd[0];
context.cond.b = instr.parsed.opd[1];
};
var sethi32 = function(instr, start, instructions) {
var addr = null;
var check = [
function(e, r) {
return e.mnem == 'sethi' && e.opd[1] == r;
},
function(e, r) {
if (e.mnem == 'nop') {
return true;
}
return (e.mnem == 'or' && e.opd[0] == r && e.opd[2] == r) || (e.mnem == 'add' && e.opd[0] == r && e.opd[2] == r);
}
];
var address = [
function(e, addr) {
var v = Long.from(parseInt(e.opd[0]).toString(16), false, 16);
return v.shl(10);
},
function(e, addr) {
var n = Long.from(parseInt(e.opd[1]).toString(16), false, 16);
return addr[e.mnem](n);
},
];
var step = 0;
var i;
for (i = start; i < instructions.length && step < check.length; ++i) {
var elem = instructions[i].parsed;
if (!check[step](elem, instr.parsed.opd[1])) {
break;
}
addr = address[step](elem, addr);
step++;
instructions[i].code = Base.nop();
}
if (addr) {
--i;
addr = '0x' + addr.toString(16);
instr.code = Base.assign(instr.parsed.opd[1], addr.replace(/0x-/, '-0x'));
}
return i;
};
var _branch_list = [
'ba', 'bn', 'be', 'bne', 'bl', 'ble', 'bge', 'bg',
'blu', 'bleu', 'bgeu', 'bgu', 'bpos', 'bneg',
'bcs', 'bcc', 'bvs', 'bvc', 'call', 'jmp', 'jmpl',
'ret', 'retl', 'rett'
];
export default {
instructions: {
add: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
addcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
addx: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
addxcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
and: function(instr, context, instructions) {
return Base.and(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
andcc: function(instr, context, instructions) {
_compare(instr, context);
return Base.and(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
andn: function(instr, context, instructions) {
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.and(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
andncc: function(instr, context, instructions) {
_compare(instr, context);
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.and(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
ba: function(instr, context, instructions) {
return Base.nop();
},
bn: function(instr, context, instructions) {
return Base.nop();
},
be: function(instr, context, instructions) {
return _conditional(instr, context, 'EQ');
},
bne: function(instr, context, instructions) {
return _conditional(instr, context, 'NE');
},
bg: function(instr, context, instructions) {
return _conditional(instr, context, 'GT');
},
bge: function(instr, context, instructions) {
return _conditional(instr, context, 'GE');
},
bl: function(instr, context, instructions) {
return _conditional(instr, context, 'LT');
},
ble: function(instr, context, instructions) {
return _conditional(instr, context, 'LE');
},
blu: function(instr, context, instructions) {
return _conditional(instr, context, 'LT');
},
bleu: function(instr, context, instructions) {
return _conditional(instr, context, 'LE');
},
bgeu: function(instr, context, instructions) {
return _conditional(instr, context, 'GE');
},
bgu: function(instr, context, instructions) {
return _conditional(instr, context, 'GT');
},
bpos: function(instr, context, instructions) {
return _conditional(instr, context, 'GE');
},
bneg: function(instr, context, instructions) {
return _conditional(instr, context, 'LT');
},
call: function(instr, context, instructions) {
return Base.call(_call_fix_name(instr.parsed.opd[0]), []);
},
cmp: _compare,
ldub: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 8);
},
ldsb: function(instr, context, instructions) {
return _load(instr, context, instructions, true, 8);
},
lduh: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 16);
},
ldsh: function(instr, context, instructions) {
return _load(instr, context, instructions, true, 16);
},
ld: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 32);
},
ldd: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 64);
},
mov: function(instr, context, instructions) {
return Base.assign(instr.parsed.opd[1], instr.parsed.opd[0]);
},
nop: function(instr) {
return Base.nop();
},
or: function(instr, context, instructions) {
return Base.or(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
orcc: function(instr, context, instructions) {
_compare(instr, context);
return Base.or(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
orn: function(instr, context, instructions) {
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.or(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
orncc: function(instr, context, instructions) {
_compare(instr, context);
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.or(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
ret: function(instr, context, instructions) {
return Base.return();
},
retl: function(instr, context, instructions) {
return Base.return();
},
rett: function(instr, context, instructions) {
return Base.return();
},
restore: function(instr, context, instructions) {
return Base.nop();
},
save: function(instr, context, instructions) {
return Base.nop();
},
sethi: function(instr, context, instructions) {
var v = Long.from(parseInt(instr.parsed.opd[0]).toString(16), true, 16);
return Base.assign(instr.parsed.opd[1], '0x' + v.shl(10).toString(16));
},
sll: function(instr, context, instructions) {
return Base.shift_left(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
srl: function(instr, context, instructions) {
return Base.shift_right(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
sra: function(instr, context, instructions) {
return Base.shift_right(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
stb: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 8);
},
sth: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 16);
},
st: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 32);
},
std: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 64);
},
sub: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
subcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
subx: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
subxcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
xor: function(instr, context, instructions) {
return Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
xorcc: function(instr, context, instructions) {
_compare(instr, context);
return Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
xnor: function(instr, context, instructions) {
var ops = [];
ops.push(Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.not(instr.parsed.opd[2], instr.parsed.opd[2]));
return Base.composed(ops);
},
xnorcc: function(instr, context, instructions) {
_compare(instr, context);
var ops = [];
ops.push(Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.not(instr.parsed.opd[2], instr.parsed.opd[2]));
return Base.composed(ops);
},
unimp: function() {
return Base.nop();
},
invalid: function() {
return Base.nop();
}
},
parse: function(assembly) {
var tokens = assembly.replace(/,/g, ' ').replace(/\[|\]/g, '').replace(/\s+/g, ' ').trim().split(' ');
return {
mnem: tokens.shift(),
opd: tokens
};
},
context: function() {
return {
cond: {
a: null,
b: null
}
};
},
preanalisys: function(instructions) {
/* delayed branch fix */
for (var i = 0; i < (instructions.length - 1); i++) {
var op = instructions[i].parsed.mnem;
var n = instructions[i + 1].parsed.mnem;
if (_branch_list.indexOf(op) >= 0 && n != 'nop' && _branch_list.indexOf(n) < 0) {
Instruction.swap(instructions, i, i + 1);
++i;
}
}
},
postanalisys: function(instructions, context) {
/* simplifies any load address 32/64 bit */
for (var i = 0; i < instructions.length; i++) {
if (instructions[i].parsed.mnem == 'sethi') {
i = sethi32(instructions[i], i, instructions);
}
}
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
+516
View File
@@ -0,0 +1,516 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from '../core/base.js';
import Variable from '../core/variable.js';
var _common_math = function(e, op, reversed) {
if (e.opd[1] == '0') {
return Base.nop();
}
if (reversed) {
return op(e.opd[1], e.opd[0], e.opd[1]);
}
return op(e.opd[1], e.opd[1], e.opd[0]);
};
var _compare = function(instr, context) {
context.cond.a = instr.parsed.opd[1];
context.cond.b = instr.parsed.opd[0];
return Base.nop();
};
var _conditional = function(instr, context, type, zero) {
instr.conditional(context.cond.a, context.cond.b, type);
return Base.nop();
};
var load_bits = function(register, pointer, bits, signed) {
//pointer, register, bits, is_signed
return Base.read_memory(pointer, register, bits, signed);
};
var store_bits = function(register, pointer, bits, signed) {
//pointer, register, bits, is_signed
return Base.write_memory(pointer, register, bits, signed);
};
var _setf_v850_cond = {
'lt': {
cond: 'LT',
arg1: null,
},
'le': {
cond: 'LE',
arg1: null,
},
'ge': {
cond: 'GE',
arg1: null,
},
'gt': {
cond: 'GT',
arg1: null,
},
'nh': {
cond: 'LE',
arg1: null,
},
'h': {
cond: 'GT',
arg1: null,
},
'nz': {
cond: 'NE',
arg1: '0',
},
'z': {
cond: 'EQ',
arg1: '0',
}
};
export default {
instructions: {
add: function(instr) {
return _common_math(instr.parsed, Base.add);
},
and: function(instr) {
return _common_math(instr.parsed, Base.and);
},
b: function() {
return Base.nop();
},
bne: function(instr, context) {
return _conditional(instr, context, 'EQ');
},
beq: function(instr, context) {
return _conditional(instr, context, 'NE');
},
bgt: function(instr, context) {
return _conditional(instr, context, 'LE');
},
bnh: function(instr, context) {
//branch not higher = LE
return _conditional(instr, context, 'GT');
},
bh: function(instr, context) {
//branch higher = GT
return _conditional(instr, context, 'LE');
},
bge: function(instr, context) {
return _conditional(instr, context, 'LT');
},
blt: function(instr, context) {
return _conditional(instr, context, 'GE');
},
ble: function(instr, context) {
return _conditional(instr, context, 'GT');
},
bz: function(instr, context) {
return _conditional(instr, context, 'NE');
},
bnz: function(instr, context) {
return _conditional(instr, context, 'EQ');
},
cmp: _compare,
jarl: function(instr, context, instructions) {
if (instr.parsed.opd[1] == '0') {
instr.comments.push('link pointer is lost. (used r0)');
} else {
instr.comments.push(instr.parsed.opd[1] + ' = PC + 4;');
}
var arg = instr.parsed.opd[0];
if (instr.parsed.opd[0].indexOf('0x') == 0) {
arg = Variable.functionPointer(arg);
}
return Base.call(arg, []);
},
jmp: function(instr, context, instructions) {
if ((instructions.length - 1) == instructions.indexOf(instr)) {
//name, args, is_pointer, returns, bits
return Base.call(instr.parsed.opd[0], [], true, 'return');
}
return Base.nop();
},
jr: function() {
return Base.nop();
},
'ld.b': function(instr) {
// ld.X 0x6c36[r4], r14
// ["ld.X","0x6c36","r4","r14"]
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, true);
}
return load_bits(dst, src + ' + ' + addr, 8, true);
},
'ld.bu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, false);
}
return load_bits(dst, src + ' + ' + addr, 8, false);
},
'ld.h': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, true);
}
return load_bits(dst, src + ' + ' + addr, 16, true);
},
'ld.hu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, false);
}
return load_bits(dst, src + ' + ' + addr, 16, false);
},
'ld.w': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 32, false);
}
return load_bits(dst, src + ' + ' + addr, 32, false);
},
mov: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.assign(instr.parsed.opd[1], instr.parsed.opd[0]);
},
movea: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
if (instr.parsed.opd[1] == '0') {
return Base.assign(instr.parsed.opd[2], instr.parsed.opd[0]);
}
if (instr.parsed.opd[0] == '0') {
return Base.assign(instr.parsed.opd[2], instr.parsed.opd[1]);
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
movhi: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
var a = instr.parsed.opd[0];
if (a.indexOf('0x') != 0) {
a = '0x' + parseInt(a).toString(16);
}
return Base.assign(instr.parsed.opd[1], a + '0000');
},
mul: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
//value, bits, is_signed, is_pointer, is_memory
var n = Variable.local(instr.parsed.opd[0], 32, true);
return Base.multiply(instr.parsed.opd[2], instr.parsed.opd[1], n);
},
mulh: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.multiply(instr.parsed.opd[1], instr.parsed.opd[1], instr.parsed.opd[0]);
},
mulhi: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
return Base.multiply(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
not: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.not(instr.parsed.opd[1], instr.parsed.opd[0]);
},
nop: function(instr) {
return Base.nop();
},
or: function(instr) {
return _common_math(instr.parsed, Base.or);
},
ori: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
return Base.or(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
satadd: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.add);
},
satsub: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.subtract, false);
},
satsubi: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.subtract, true);
},
satsubr: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.subtract, true);
},
shl: function(instr) {
return _common_math(instr.parsed, Base.shift_left);
},
shr: function(instr) {
//logically shift right
return _common_math(instr.parsed, Base.shift_right);
},
setf: function(instr, context) {
var e = instr.parsed;
if (e.opd[1] == '0') {
return Base.nop();
}
if (e.opd[0] == 'v' || e.opd[0] == 'nv') {
var m = new Variable.macro((e.opd[0] == 'nv' ? '!' : '') + 'IS_OVERFLOW(' + context.cond.a + ', ' + context.cond.b + ')');
var op = Base.conditional_assign(e.opd[1], m, null, 'CUST', '1', '0');
Global().context.addMarcro('#define IS_OVERFLOW(a,b) (((a<0)&&(b<0)&&(a+b>0))||((a>0)&&(b>0)&&(a+b<0)))');
return op;
}
var o = _setf_v850_cond[e.opd[0]];
if (!o) {
instr.comments.push('unhandled use-case. please report it.');
instr.comments.push(instr.assembly);
return Base.nop();
}
return Base.conditional_assign(e.opd[1], context.cond.a, o.arg1 || context.cond.b, o.cond, '1', '0');
},
'sld.b': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, true);
}
return load_bits(dst, src + ' + ' + addr, 8, true);
},
'sld.bu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, false);
}
return load_bits(dst, src + ' + ' + addr, 8, false);
},
'sld.h': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, true);
}
return load_bits(dst, src + ' + ' + addr, 16, true);
},
'sld.hu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, false);
}
return load_bits(dst, src + ' + ' + addr, 16, false);
},
'sld.w': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 32, false);
}
return load_bits(dst, src + ' + ' + addr, 32, false);
},
'sst.b': function(instr) {
// st.X , r14, 0x6c36[r4]
// ["st.X","r14","0x6c36","r4"]
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, true);
}
return store_bits(dst, src + ' + ' + addr, 8, true);
},
'sst.bu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, false);
}
return store_bits(dst, src + ' + ' + addr, 8, false);
},
'sst.h': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, true);
}
return store_bits(dst, src + ' + ' + addr, 16, true);
},
'sst.hu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, false);
}
return store_bits(dst, src + ' + ' + addr, 16, false);
},
'sst.w': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 32, false);
}
return store_bits(dst, src + ' + ' + addr, 32, false);
},
'st.b': function(instr) {
// st.X , r14, 0x6c36[r4]
// ["st.X","r14","0x6c36","r4"]
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, true);
}
return store_bits(dst, src + ' + ' + addr, 8, true);
},
'st.bu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, false);
}
return store_bits(dst, src + ' + ' + addr, 8, false);
},
'st.h': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, true);
}
return store_bits(dst, src + ' + ' + addr, 16, true);
},
'st.hu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, false);
}
return store_bits(dst, src + ' + ' + addr, 16, false);
},
'st.w': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 32, false);
}
return store_bits(dst, src + ' + ' + addr, 32, false);
},
sub: function(instr) {
return _common_math(instr.parsed, Base.subtract);
},
subr: function(instr) {
return _common_math(instr.parsed, Base.subtract, true);
},
sxb: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.extend(instr.parsed.opd[1], instr.parsed.opd[0], 32);
},
sxh: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.extend(instr.parsed.opd[1], instr.parsed.opd[0], 32);
},
tst: function(instr, context, instructions) {
var e = instr.parsed;
context.cond.a = (e.opd[0] == e.opd[1]) ? e.opd[1] : "(" + e.opd[1] + " & " + e.opd[0] + ")";
context.cond.b = '0';
return Base.nop();
},
xor: function(instr) {
return _common_math(instr.parsed, Base.xor);
},
xori: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
return Base.xor(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
zxb: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
var a = Variable.local(instr.parsed.opd[0], 32, false);
return Base.assign(instr.parsed.opd[1], a);
},
zxh: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
var a = Variable.local(instr.parsed.opd[0], 32, false);
return Base.assign(instr.parsed.opd[1], a);
},
invalid: function() {
return Base.nop();
}
},
parse: function(assembly) {
var ret = assembly.replace(/\[|\]/g, ' ').replace(/,/g, ' ');
ret = ret.replace(/\{|\}/g, ' ').replace(/\s+/g, ' ');
ret = ret.trim().replace(/\br0\b/g, '0').split(' ');
return {
mnem: ret.shift(),
opd: ret
};
},
context: function() {
return {
cond: {
a: '?',
b: '?'
},
leave: false,
vars: []
};
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
+544
View File
@@ -0,0 +1,544 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from '../core/base.js';
import Variable from '../core/variable.js';
import Extra from '../core/extra.js';
var _memory_name = "_memory";
var _to_argument = function(wasm_var) {
return wasm_var.toString('arg');
};
var WasmVar = function(name, type, instr) {
this.name = name;
this.type = type;
this.instr = instr;
this.toString = function(s) {
if (s == 'arg') {
return this.type + ' ' + this.name;
}
return this.name;
};
};
var StackVar = function(type, instr) {
return new WasmVar(Variable.uniqueName('stack'), type, instr);
};
var _is_next_a_set = function(instr, instructions) {
var pos = instructions.indexOf(instr) + 1;
if (!instructions[pos]) {
return false;
}
var mnem = instructions[pos].parsed.mnem;
return mnem == 'set_local' || mnem == 'set_global' ? pos : -1;
};
var _is_next_local = function(instr, instructions) {
var pos = instructions.indexOf(instr) + 1;
if (!instructions[pos]) {
return false;
}
var mnem = instructions[pos].parsed.mnem;
return mnem == 'set_local' ? pos : -1;
};
var _is_previous_call = function(instr, instructions) {
var pos = instructions.indexOf(instr) - 1;
if (!instructions[pos]) {
return false;
}
var mnem = instructions[pos].parsed.mnem;
return mnem == 'call' ? pos : -1;
};
var _set_local = function(instr, context, instructions, type, allow_args) {
var pos = _is_next_local(instr, instructions);
var name = allow_args ? 'arg_' : 'local';
var n = '';
if (pos < 0) {
n = instr.parsed.opd[0];
if (!context.local[n]) {
name += n;
context.local[n] = new WasmVar(name, type, instr);
if (allow_args) {
context.input[n] = context.local[n];
}
}
return context.local[n];
}
n = instructions[pos].parsed.opd[0];
if (!context.local[n]) {
name += n;
context.local[n] = new WasmVar(name, type, instr);
if (allow_args) {
context.input[n] = context.local[n];
}
}
return context.local[n];
};
var _set_global = function(instr, context, instructions, type) {
var n = instr.parsed.opd[0].trim();
if (!context.global[n]) {
context.global[n] = new WasmVar('global_' + instr.parsed.opd[0], type, instr);
}
return context.global[n];
};
var _bits = function(o) {
if (typeof o == 'object') {
o = o.parsed.type;
}
switch (o) {
case 'f32':
return 32;
case 'f64':
return 64;
case 'i64':
return 64;
default:
return 32;
}
};
var _type = function(o, unsigned) {
if (typeof o == 'object') {
o = o.parsed.type;
}
switch (o) {
case 'f32':
return 'float';
case 'f64':
return 'double';
case 'i64':
return unsigned ? 'uint64_t' : 'int64_t';
default:
return unsigned ? 'uint32_t' : 'int32_t';
}
};
var _remove_const = function(instr, instructions, stackval) {
if (stackval && instructions.indexOf(stackval.instr) == (instructions.indexOf(instr) - 1) && stackval.instr.parsed.mnem == 'const') {
stackval.instr.valid = false;
// <type>.const <N>
return stackval.instr.parsed.opd[0];
}
return stackval;
};
var _math = function(instr, context, instructions, type, op) {
var source_b = context.stack.pop();
source_b = _remove_const(instr, instructions, source_b);
var source_a = context.stack.pop();
source_a.type = type;
source_b.type = type;
var pos = _is_next_a_set(instr, instructions);
var destination = StackVar(type, instr);
context.stack.push(destination); // push must happen.
if (pos < 0) {
return op(destination.toString(), source_a.toString(), source_b.toString());
}
var next_set = instructions[pos];
next_set.valid = false;
if (next_set.parsed.mnem == 'set_local') {
destination = _set_local(next_set, context, instructions, 'int32_t', false);
} else {
destination = _set_global(next_set, context, instructions, 'int32_t');
}
return op(destination.toString(), source_a.toString(), source_b.toString());
};
var _cmp = {
eq: 'EQ',
ne: 'NE',
eqz: 'EQ',
nez: 'NE',
gt_s: 'GT',
gt_u: 'GT',
ge_s: 'GE',
ge_u: 'GE',
lt_s: 'LT',
lt_u: 'LT',
le_s: 'LE',
le_u: 'LE',
gt: 'GT',
ge: 'GE',
lt: 'LT',
le: 'LE'
};
var _conditional = function(instr, context, instructions) {
var cond = {};
cond.b = context.stack.pop().toString();
cond.a = context.stack.pop().toString();
if (!cond.a) {
cond.a = '?';
}
if (!cond.b) {
cond.b = '?';
}
cond.cmp = _cmp[instr.parsed.mnem];
context.condstack.push(cond);
return Base.nop();
};
var _conditional_zero = function(instr, context, instructions) {
var cond = {};
cond.b = '0';
cond.a = context.stack.pop().toString();
if (!cond.a) {
cond.a = '?';
}
cond.cmp = _cmp[instr.parsed.mnem];
context.condstack.push(cond);
return Base.nop();
};
var _set_instruction_conditional = function(instr, context) {
var cond = context.condstack.pop();
if (!cond) {
var arg = context.stack.pop();
if (!arg) {
arg = '?';
}
instr.conditional(arg.toString(), '0', 'NE');
} else {
instr.conditional(cond.a, cond.b, cond.cmp);
}
};
var _common_load = function(instr, context) {
context.memory = true;
var offset = instr.parsed.opd[instr.parsed.opd.length - 1];
var pointer = context.stack.pop().toString();
var register = StackVar(_type(instr), instr);
context.stack.push(register);
if (offset != '0') {
var bits = instr.parsed.mnem.match(/\d+/) || ["32"];
bits = parseInt(bits[0]) / 8;
pointer += ' + ' + (parseInt(offset) / bits).toString();
}
pointer = _memory_name + ' + ' + pointer;
return Base.read_memory(pointer, register.toString(), _bits(instr), instr.parsed.mnem.endsWith('_s'));
};
var _common_store = function(instr, context) {
context.memory = true;
var offset = instr.parsed.opd[instr.parsed.opd.length - 1];
var register = context.stack.pop().toString();
var pointer = context.stack.pop().toString();
var bits = instr.parsed.mnem.match(/\d+/) || ["32"];
bits = parseInt(bits[0]);
if (offset != '0') {
pointer += ' + ' + (parseInt(offset) / (bits / 8)).toString();
}
pointer = _memory_name + ' + ' + pointer;
return Base.write_memory(pointer, register.toString(), bits, false);
};
var _wasm_arch = {
instructions: {
eq: _conditional,
ne: _conditional,
eqz: _conditional_zero,
nez: _conditional_zero,
gt_s: _conditional,
gt_u: _conditional,
ge_s: _conditional,
ge_u: _conditional,
lt_s: _conditional,
lt_u: _conditional,
le_s: _conditional,
le_u: _conditional,
gt: _conditional,
ge: _conditional,
lt: _conditional,
le: _conditional,
const: function(instr, context, instructions) {
var s = StackVar('const ' + _type(instr), instr);
context.stack.push(s);
var num = parseInt(instr.parsed.opd[0]);
if (num > 1023) {
num = '0x' + num.toString(16);
}
return Base.assign(s.toString(), num.toString());
},
load: _common_load,
load8_s: _common_load,
load8_u: _common_load,
load16_s: _common_load,
load16_u: _common_load,
store: _common_store,
store8: _common_store,
store16: _common_store,
store32: _common_store,
add: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.add);
},
and: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.and);
},
div_s: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.divide);
},
div_u: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr, true), Base.divide);
},
extend_s: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr));
}
return Base.extend(s.toString(), b.toString(), _type(instr));
},
extend_u: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
mul: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.multiply);
},
or: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.or);
},
reinterpret: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.assign(s.toString('arg'), b.toString());
}
return Base.assign(s.toString(), b.toString());
},
rem_s: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.module);
},
rem_u: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr, true), Base.module);
},
shl: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.shift_left);
},
shr_s: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.shift_right);
},
shr_u: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr, true), Base.shift_right);
},
sub: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.subtract);
},
wrap: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
trunc_s: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
trunc_u: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
xor: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.xor);
},
get_global: function(instr, context, instructions) {
var dst = _set_global(instr, context, instructions, 'int32_t');
context.stack.push(dst);
return Base.nop();
},
set_global: function(instr, context, instructions) {
var dst = _set_global(instr, context, instructions, 'int32_t');
var arg = context.stack.pop();
return Base.assign(dst.toString(), arg ? arg.toString() : "?");
},
get_local: function(instr, context, instructions) {
context.stack.push(_set_local(instr, context, instructions, 'int32_t', true));
return Base.nop();
},
set_local: function(instr, context, instructions) {
var dst = _set_local(instr, context, instructions, 'int32_t', false);
var pos = _is_previous_call(instr, instructions);
if (pos > -1) {
var call = instructions[pos];
call.code = Base.assign(dst.toString(), call.code);
return Base.nop();
}
var arg = context.stack.pop();
return Base.assign(dst.toString(), arg ? arg.toString() : "?");
},
tee_local: function(instr, context, instructions) {
var dst = _set_local(instr, context, instructions, 'int32_t', true);
var pos = _is_previous_call(instr, instructions);
if (pos > -1) {
var call = instructions[pos];
call.code = Base.assign(dst.toString(), call.code);
return Base.nop();
}
var arg = context.stack[context.stack.length - 1];
return Base.assign(dst.toString(), arg.toString());
},
drop: function(instr, context, instructions) {
_remove_const(instr, instructions, context.stack.pop());
return Base.nop();
},
call: function(instr, context, instructions) {
var args = [];
for (var i = instructions.indexOf(instr) - 1; i >= 0; i--) {
var previous = instructions[i].parsed.mnem;
if (!previous.startsWith('get_') && previous != 'const') {
break;
}
args.unshift(context.stack.pop());
}
if (instr.parsed.opd[0].match(/^\d+$/)) {
return Base.call('fcn_' + instr.parsed.opd[0], args);
}
return Base.call(instr.parsed.opd[0], args);
},
return: function(instr, context, instructions) {
var ret = null;
if (context.stack.length > 0) {
if (context.stack.length > 1) {
Global().warning('[wasm] stack len is not zero: ' + context.stack.length);
}
context.returned = context.stack.pop();
ret = _remove_const(instr, instructions, context.returned);
if (!Extra.is.string(ret)) {
ret = context.returned.toString();
}
}
return Base.return(ret);
},
'if': function(instr, context, instructions) {
_set_instruction_conditional(instr, context);
return Base.nop();
},
br_if: function(instr, context, instructions) {
_set_instruction_conditional(instr, context);
return Base.nop();
},
'else': function(instr, context, instructions) {
return Base.nop();
},
block: function(instr, context, instructions) {
return Base.nop();
},
loop: function(instr, context, instructions) {
return Base.nop();
},
end: function(instr, context, instructions) {
if (instr.jump && instr.jump.lte(instr.location)) {
_set_instruction_conditional(instr, context);
} else {
var curidx = instructions.indexOf(instr);
if (curidx == (instructions.length - 1)) {
var ret = null;
if (context.stack.length > 0) {
if (context.stack.length > 1) {
Global().warning('[wasm] stack len is not zero: ' + context.stack.length);
}
context.returned = context.stack.pop();
ret = _remove_const(instr, instructions, context.returned);
if (!Extra.is.string(ret)) {
ret = ret.toString();
}
}
return Base.return(ret);
}
}
return Base.nop();
},
br: function(instr, context, instructions) {
return Base.nop();
},
nop: function(instr, context, instructions) {
return Base.nop();
},
invalid: function(instr, context, instructions) {
return Base.nop();
}
},
parse: function(asm) {
asm = asm.trim().replace(/\s+/g, ' ').replace(/\//g, ' ');
var type = asm.match(/[if]\d\d\./);
if (type) {
type = type[0];
asm = asm.replace(/[if]\d\d\./, '');
}
asm = asm.split(' ');
return {
type: type || 'i32',
mnem: asm.shift(),
opd: asm
};
},
context: function() {
return {
returned: null,
global: {},
input: {},
local: {},
stack: [],
condstack: [],
memory: false,
};
},
globalvars: function(context) {
var to_return = Extra.to.array(context.global).map(_to_argument);
if (context.memory) {
to_return.unshift("extern uint8_t " + _memory_name + "[]");
}
return to_return;
},
localvars: function(context) {
var vars = [];
for (var k in context.local) {
var o = context.local[k];
if (Extra.is.inObject(context.input, o) || Extra.is.inObject(context.global, o)) {
continue;
}
vars.push(o.toString('arg'));
}
return vars;
},
arguments: function(context) {
return Extra.to.array(context.input).map(_to_argument);
},
returns: function(context) {
if (context.returned) {
return context.returned.type.replace(/const\s/, '');
}
return 'void';
}
};
export default _wasm_arch;
File diff suppressed because it is too large. Load diff
+34
View File
@@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import _6502 from './arch/6502.js';
import _8051 from './arch/8051.js';
import arm from './arch/arm.js';
import avr from './arch/avr.js';
import dalvik from './arch/dalvik.js';
import m68k from './arch/m68k.js';
import mips from './arch/mips.js';
import ppc from './arch/ppc.js';
import riscv from './arch/riscv.js';
import sh from './arch/sh.js';
import sparc from './arch/sparc.js';
import v850 from './arch/v850.js';
import wasm from './arch/wasm.js';
import x86 from './arch/x86.js';
export default {
'6502': _6502,
'8051': _8051,
arm: arm,
avr: avr,
dalvik: dalvik,
m68k: m68k,
mips: mips,
ppc: ppc,
riscv: riscv,
sh: sh,
sparc: sparc,
v850: v850,
wasm: wasm,
x86: x86
};
+51
View File
@@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
var __colors = {
black: [30, 39],
red: [31, 39],
green: [32, 39],
yellow: [33, 39],
blue: [34, 39],
magenta: [35, 39],
cyan: [36, 39],
white: [37, 39],
gray: [90, 39],
};
function pair(name, n) {
if (name.length === 6) {
n *= 2;
return parseInt(name.substring(n, n + 2), 16);
}
return (parseInt(name.substring(n, n + 1), 16) << 4) >>> 0;
}
var Color = function(name) {
var fn = (function(){
var that = function(x) {
return that.open + x + that.close;
};
return that;
})();
if (name.startsWith('rgb:')) {
name = name.substring(4);
const str = '38;2;' + pair(name, 0) + ';' + pair(name, 1) + ';' + pair(name, 2);
fn.open = '\u001b[' + str + 'm';
fn.close = '\u001b[39m';
} else {
if (!__colors[name]) {
throw new Error('Invalid name: ' + name);
}
fn.open = '\u001b[' + __colors[name][0] + 'm';
fn.close = '\u001b[' + __colors[name][1] + 'm';
}
return fn;
};
Color.make = function(theme) {
var g = {};
for (var key in theme) {
g[key] = Color(theme[key]);
}
return g;
};
export default Color;
+17
View File
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
var Color = function(name) {
var fn = function(x) {
return x;
};
return fn;
};
Color.make = function(theme) {
var g = {};
for (var key in theme) {
g[key] = Color(theme[key]);
}
return g;
};
export default Color;
+167
View File
@@ -0,0 +1,167 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
export default function() {
this.lines = [];
this.errors = [];
this.log = [];
/**
* Print a line of decompiled code.
* @param str - content of the line
* @param offset - offset of the original instruction (optional)
*/
this.printLine = function(str, offset) {
var line = { str: str, offset: offset };
this.lines.push(line);
};
/**
* Print a line for logging.
* @param str - content to print
* @param error - boolean whether this is an error (optional)
*/
this.printLog = function(str, error) {
if (Global().evars.extra.json) {
if(error) {
this.errors.push(str);
} else {
this.log.push(str);
}
} else {
console.log(str);
}
};
/**
* Internal C macro list.
* @type {Array}
*/
this.macros = ['#include <stdint.h>'];
/**
* Adds a C macro string to the global list of macros.
* @param {String} - item to add
*/
this.addMacro = function(x) {
if (this.macros.indexOf(x) < 0) {
this.macros.push(x);
}
};
/**
* prints all the macros. used internally by core.js
*/
this.printMacros = function(offset) {
if (!Global().evars.honor.blocks) {
var t = Global().printer.theme;
for (var i = 0; i < this.macros.length; i++) {
this.printLine(this.identfy() + t.macro(this.macros[i]), offset);
}
}
this.printLine(this.identfy() + ' ', offset);
};
/**
* List of dependencies (mostly generic functions like rotate, etc..)
* that cannot be described easily from a asm opcode.
* @type {Array}
*/
this.dependencies = [];
/**
* adds a dependency to the global list.
* @param {String|Object} - item to add
*/
this.addDependency = function(x) {
if (this.dependencies.indexOf(x) < 0) {
this.dependencies.push(x);
}
};
/**
* prints all the dependencies. used internally by core.js
*/
this.printDependencies = function(offset) {
if (Global().evars.honor.blocks) {
return;
}
this.dependencies.forEach(function(x) {
x.print(offset);
});
if (this.dependencies.length > 0) {
this.printLine(this.identfy() + ' ', offset);
}
};
/**
* Assembly identation "constant"
* @type {String}
*/
this.identAsm = '';
/**
* Sets the max size of the identation line for the `--assembly/jsdec.asm` option.
* @param {Number} size - Size to set
*/
this.identAsmSet = function(size) {
// size = 0x + addr + space + asm + space
size += 10;
while (this.identAsm.length < size) {
this.identAsm += ' ';
}
};
/**
* Compare the max size of the identation line with the given one.
* @param {Number} size - Size to set
* @return {Number}
*/
this.identCompare = function(size) {
// size = 0x + addr + space + asm + space
return size - ((this.identAsm.length / 4) - 10);
};
/**
* Scope identation
* @type {String}
*/
this.ident = '';
/**
* Adds spaces per each scope going in.
*/
this.identIn = function() {
this.ident += ' ';
};
/**
* Removes spaces per each scope going out.
*/
this.identOut = function(force) {
this.ident = this.ident.substr(4, this.ident.length);
};
/**
* Returns the data to be used for line identation.
* It's used mostly internally when a line is going to be printed on screen.
* @param {Number} size_no_colors - Size of the strings without ansi colors
* @param {String} string_to_print - String to be printed before the pipe
* @param {Boolean} disable_identation - Force to not set the scope identation of the line.
* @return {string} - Identation including eventual string to be printed.
*/
this.identfy = function(size_no_colors, string_to_print, disable_identation) {
var ident = disable_identation ? '' : this.ident;
if (Global().evars.honor.assembly && !Global().evars.honor.blocks) {
string_to_print = string_to_print || '';
size_no_colors = size_no_colors || 0;
return ' ' + string_to_print + this.identAsm.substring(size_no_colors, this.identAsm.length) + ' | ' + ident;
} else if (Global().evars.honor.offsets && !Global().evars.honor.blocks) {
string_to_print = string_to_print || '';
size_no_colors = size_no_colors || 0;
return ' ' + string_to_print + this.identAsm.substring(size_no_colors, 14) + ' | ' + ident;
}
return ident;
};
}
+214
View File
@@ -0,0 +1,214 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from './core/base.js';
import Block from './core/block.js';
import Scope from './core/scope.js';
import Extra from './core/extra.js';
import Strings from './core/strings.js';
import Symbols from './core/symbols.js';
import Classes from './core/classes.js';
import Functions from './core/functions.js';
import Instruction from './core/instruction.js';
import ControlFlow from './core/controlflow.js';
import XRefs from './core/xrefs.js';
/**
* Fixes for known routine names that are standard (like main)
* @param {String} routine_name Routine name
* @param {String} return_type Return type
* @return {String} New return type
*/
var _hardcoded_fixes = function(routine_name, return_type) {
if (Extra.replace.call(routine_name) == "main") {
return 'int32_t';
}
return return_type || 'void';
};
/**
* Is the function that is called after the opcode analisys.
* Essentially analyze the flows and allows the call of
* the `postanalisys` function that has to be set in the architecture.
* @param {Object} session - Current session object.
* @param {Object} arch - Current architecture object
* @param {Object} arch_context - Current architecture context object.
*/
var _post_analysis = function(session, arch, arch_context) {
ControlFlow(session);
if (arch.postanalisys) {
arch.postanalisys(session.instructions, arch_context);
}
var routine_name = arch.routine_name ? arch.routine_name(session.routine_name) : Extra.replace.call(session.routine_name);
if (session.instructions.length < 1) {
return;
}
var routine = new Scope.routine(session.instructions[0].location, {
returns: _hardcoded_fixes(session.routine_name, arch.returns(arch_context)),
name: session.routine_name,
routine_name: routine_name,
args: arch.arguments(arch_context) || [],
locals: arch.localvars(arch_context) || [],
globals: arch.globalvars(arch_context) || []
});
session.routine = routine;
};
/**
* Is the function that is called before the opcode analisys.
* Calls `preanalisys` function that has to be set in the architecture
* and copies the instruction into the first block and updates the bounds of this.
* @param {Object} session - Current session object.
* @param {Object} arch - Current architecture object
* @param {Object} arch_context - Current architecture context object.
*/
var _pre_analysis = function(session, arch, arch_context) {
if (arch.preanalisys) {
arch.preanalisys(session.instructions, arch_context);
}
session.blocks[0].instructions = session.instructions.slice();
session.blocks[0].update();
};
/**
* Most important of the analisys block: it analize the architecture opcodes.
* @param {Object} session - Current session object.
* @param {Object} arch - Current architecture object
* @param {Object} arch_context - Current architecture context object.
*/
var _decompile = function(session, arch, arch_context) {
var instructions = session.blocks[0].instructions;
for (var i = 0; i < instructions.length; i++) {
var instr = instructions[i];
if (!instr.parsed.mnem || instr.parsed.mnem.length < 1) {
Global().warning("invalid mnem. stopping instruction analysis.");
break;
}
var fcn = arch.instructions[instr.parsed.mnem];
// Global().context.printLine(instr.assembly)
instr.code = fcn ? fcn(instr, arch_context, instructions) : new Base.unknown(instr.assembly);
}
};
/**
* Prints the current session into the screen.
* @param {Object} session - Current session object.
*/
var _print = function(session) {
var lineoff = session.instructions.length > 0 ? session.instructions[0].location : null;
if (!session.routine) {
Global().context.printLog('Error: no "good" data given (all invalid opcodes).', true);
return;
}
if (Global().evars.extra.ascomment) {
session.ascomment();
Global().context.printLog('[jsdec] comments applied for "' + session.routine_name + '".');
return;
} else if (Global().evars.extra.ascodeline) {
session.ascodeline();
Global().context.printLog('[jsdec] new code lines applied for "' + session.routine_name + '".');
return;
}
if (!Global().evars.extra.allfunctions) {
var t = Global().printer.theme;
var asm_header = Global().evars.honor.offsets ? '' : '; assembly';
var details = '/* ' + Global().evars.extra.file + ' @ 0x' + Global().evars.extra.offset.toString(16) + ' */';
Global().context.printLine(Global().context.identfy(asm_header.length, t.comment(asm_header)) + t.comment('/* jsdec pseudo code output */'), lineoff);
Global().context.printLine(Global().context.identfy() + t.comment(details), lineoff);
if (['java', 'dalvik'].indexOf(Global().evars.arch) < 0) {
Global().context.printMacros(lineoff);
Global().context.printDependencies(lineoff);
}
}
session.print();
lineoff = session.instructions.length > 0 ? session.instructions[session.instructions.length - 1].location : null;
while (Global().context.ident.length > 0) {
Global().context.identOut();
var value = Global().context.identfy() + '}';
Global().context.printLine(value, lineoff);
}
};
/**
* Defines the structure that will be used as session for analisys steps.
* @param {Object} data - Data to be analized.
* @param {Object} arch - Current architecture object
*/
var _session = function(data, arch) {
this.blocks = [new Block()];
var instructions = [];
var symbols = new Symbols(data.xrefs.symbols);
var strings = new Strings(data.xrefs.strings);
var classes = new Classes(data.xrefs.classes);
var functions = new Functions(data.xrefs.functions);
var max_length = 0;
var max_address = 8;
Global().xrefs = new XRefs(strings, symbols, classes);
for (var i = 0; i < data.graph[0].blocks.length; i++) {
var block = data.graph[0].blocks[i];
// This is hacky but it is required by wasm..
if (data.arch == 'wasm') {
var last = block.ops[block.ops.length - 1];
if (!last.jump) {
last.jump = block.jump;
}
}
instructions = instructions.concat(block.ops.filter(function(b) {
return b.opcode != null;
}).map(function(b) {
if (max_length < b.opcode.length) {
max_length = b.opcode.length;
}
var ins = new Instruction(b, arch, i);
if (max_address < ins.location.toString(16)) {
max_address = ins.location.toString(16).length;
}
ins.symbol = symbols.search(ins.pointer || ins.jump);
ins.string = strings.search(ins.pointer);
ins.klass = classes.search(ins.pointer);
ins.callee = functions.search(ins.jump);
return ins;
}));
}
this.routine_name = data.graph[0].name;
if (max_length < this.routine_name.length) {
max_length = this.routine_name.length;
}
Global().context.identAsmSet(max_address + (max_length < this.routine_name.length ? this.routine_name.length : max_length));
this.instructions = instructions.filter(function(op, p, ops) {
for (var i = p - 1; i >= 0; i--) {
if (ops[i].location.eq(op.location)) {
return false;
}
}
return true;
});
this.ascomment = function() {
for (var i = 0; i < this.blocks.length; i++) {
this.blocks[i].ascomment();
}
};
this.ascodeline = function() {
for (var i = 0; i < this.blocks.length; i++) {
this.blocks[i].ascodeline();
}
};
this.print = function() {
this.routine.print();
for (var i = 0; i < this.blocks.length; i++) {
this.blocks[i].print();
}
};
};
export default {
decompile: _decompile,
session: _session,
analysis: {
pre: _pre_analysis,
post: _post_analysis
},
print: _print,
};
+522
View File
@@ -0,0 +1,522 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-FileCopyrightText: 2018-2019 elicn
// SPDX-License-Identifier: BSD-3-Clause
import Cpp from '../db/cpp.js';
import CCalls from '../db/c_calls.js';
import Extra from './extra.js';
import Variable from './variable.js';
import Condition from './condition.js';
import Long from '../long.js';
/**
* Wraps a string with parenthesis.
* @param {string} s A string to wrap
* @returns {string} `s` wrapped by parenthesis
*/
var parenthesize = function(s) {
return ['(', s, ')'].join('');
};
/**
* Wraps a string with parenthesis only if it is complex.
* @param {string} s A string to wrap
* @returns {string} `s` wrapped by parenthesis if `s` is a complex string, and `s` otherwise
*/
var autoParen = function(s) {
return (s.indexOf(' ') > (-1) ? parenthesize(s) : s);
};
var autoString = function(v) {
v = v || "";
return Extra.is.string(v) ? Global().printer.auto(v) : v.toString();
};
var _generic_asm = function(asm) {
this.asm = asm;
this.toString = function() {
return Global().printer.theme.callname('__asm') + ' (' + Global().printer.theme.text('"' + this.asm + '"') + ')';
};
};
/**
* Unary expression
* @constructor
* @inner
*/
var _uexpr = function(operator, operand) {
this.operator = operator;
this.operands = [
autoString(operand)
];
/** @returns {!string} */
this.toString = function() {
return [
this.operator,
this.operands[0]
].join('');
};
};
/**
* Unary expression with postfix notation
* @constructor
* @inner
*/
var _uexpr_pf = function(operator, operand) {
_uexpr.call(this, operator, [operand]);
/** @returns {!string} */
this.toString = function() {
return [
this.operands[0],
this.operator,
].join('');
};
};
_uexpr_pf.prototype = Object.create(_uexpr.prototype);
/**
* Binary expression
* @constructor
* @inner
*/
var _bexpr = function(operator, lhand, rhand) {
this.operator = operator;
this.operands = [
autoString(lhand),
autoString(rhand)
];
/** @returns {!string} */
this.toString = function() {
return [
this.operands[0],
this.operator,
this.operands[1]
].join(' ');
};
};
/**
* Ternary expression
* @constructor
* @inner
*/
var _texpr = function(operator1, operator2, operand1, operand2, operand3) {
this.operators = [operator1, operator2];
this.operands = [
autoParen(autoString(operand1)),
autoParen(autoString(operand2)),
autoParen(autoString(operand3))
];
/** @returns {!string} */
this.toString = function() {
return [
this.operands[0],
this.operators[0],
this.operands[1],
this.operators[1],
this.operands[2]
].join(' ');
};
};
var _assign = function(lhand, rhand) {
if (lhand == rhand) {
return '';
}
if ((rhand instanceof _bexpr) && (autoString(lhand) == rhand.operands[0])) {
return new _bexpr(rhand.operator + '=', lhand, rhand.operands[1]);
}
if (rhand instanceof Variable.functionPointer) {
rhand = parenthesize(rhand);
}
return new _bexpr('=', lhand, rhand);
};
var _cast = function(source, type) {
return new _uexpr(parenthesize(Global().printer.theme.types(type)) + ' ', source);
};
var _generic_call = function(function_name, args) {
this.function_name = Extra.is.string(function_name) ? Cpp(Extra.replace.call(function_name)) : function_name;
this.callargs = args || [];
this.toString = function() {
var fname = this.function_name;
if (Extra.is.string(fname)) {
fname = Global().printer.theme.callname(fname);
}
return [fname, parenthesize(this.callargs.join(', '))].join(' ');
};
};
var _generic_method_call = function(object_this, function_name, args, method_sep, prefix, postfix) {
this.object_this = Extra.is.string(object_this) ? Cpp(object_this) : object_this;
this.function_name = Extra.is.string(function_name) ? Cpp(function_name) : function_name;
this.callargs = args || [];
this.method_sep = method_sep;
this.prefix = prefix || "";
this.postfix = postfix || "";
this.toString = function() {
var fname = this.function_name;
if (Extra.is.string(fname)) {
fname = Global().printer.theme.callname(fname);
}
return this.prefix + this.object_this + this.method_sep + [fname, parenthesize(this.callargs.join(', '))].join(' ') + this.postfix;
};
};
var _generic_rotate = function(destination, source_a, rotation, bits, is_left) {
this.call = 'rotate_' + (is_left ? 'left' : 'right') + bits;
this.destination = destination;
this.source_a = source_a;
this.rotation = Extra.is.number(rotation) ? ("0x" + rotation.toString(16)) : rotation;
this.toString = function() {
var args = [autoString(this.source_a), autoString(this.rotation)];
return [autoString(this.destination), '=',
Global().printer.theme.callname(this.call),
parenthesize(args.join(', '))
].join(' ');
};
};
var _generic_return = function(value) {
this.value = value;
this.toString = function(options) {
var value = '';
if (this.value) {
value = ' ' + autoString(this.value);
}
return Global().printer.theme.flow('return') + value;
};
};
var _generic_goto = function(label_or_address) {
this.value = label_or_address;
this.toString = function(options) {
return [Global().printer.theme.flow('goto'), autoString(this.value)].join(' ');
};
};
var _generic_flow = function(name) {
this.name = name;
this.toString = function(options) {
return Global().printer.theme.flow(this.name);
};
};
var _assign_object_field = function(destination, object, field, method_sep, is_from) {
this.destination = destination;
this.object = object;
this.field = field;
this.method_sep = method_sep;
this.is_from = is_from;
this.toString = function(options) {
if (this.is_from) {
return [
this.object + this.method_sep + this.field,
'=',
this.destination
].join(' ');
}
return [
this.destination,
'=',
this.object + this.method_sep + this.field
].join(' ');
};
};
var _assign_array_at = function(destination, source, index, is_from) {
this.destination = destination;
this.source = source;
this.index = index;
this.is_from = is_from;
this.toString = function(options) {
if (this.is_from) {
return [
this.destination,
'=',
this.source,
'[' + this.index + ']'
].join(' ');
}
return [
this.destination,
'[' + this.index + ']',
'=',
this.source
].join(' ');
};
};
var _generic_throw = function(value) {
this.value = value;
this.toString = function(options) {
var value = '';
if (this.value) {
value = ' ' + autoString(this.value);
}
return Global().printer.theme.flow('throw') + value;
};
};
var _generic_objc_call = function(object_this, function_name, function_arguments) {
this.object_this = object_this;
this.function_name = function_name;
this.callargs = function_arguments || [];
this.toString = function() {
var fname = this.object_this;
if (Extra.is.string(object_this)) {
fname = Global().printer.theme.callname(object_this);
}
return "[" + [fname, this.function_name].concat(this.callargs).join(' ') + "]";
};
};
export default {
/* COMMON */
assign: _assign,
cast: function(destination, source, type) {
return _assign(destination, new _cast(source, type));
},
nop: function(asm) {
return null;
},
/* JUMPS */
goto: function(label_or_address) {
return new _generic_goto(label_or_address);
},
call: function(function_name, function_arguments) {
return new _generic_call(function_name, function_arguments);
},
return: function(value) {
return new _generic_return(value);
},
break: function(value) {
return new _generic_flow('break');
},
continue: function(value) {
return new _generic_flow('continue');
},
/* BRANCHES */
conditional_assign: function(destination, source_a, source_b, cond, src_true, src_false) {
var condition = new Condition.convert(source_a, source_b, cond, false);
return _assign(destination, new _texpr('?', ':', condition.toString(), src_true, src_false));
},
conditional_math: function(destination, source_a, source_b, cond, math_operand_a, math_operand_b, src_false, operation) {
var condition = new Condition.convert(source_a, source_b, cond, false);
var src_true = new _bexpr(operation, math_operand_a, math_operand_b);
return _assign(destination, new _texpr('?', ':', condition.toString(), src_true, src_false));
},
/* MATH */
increase: function(destination, source) {
if (source == '1') {
return new _uexpr_pf('++', destination);
}
return _assign(destination, new _bexpr('+', destination, source));
},
decrease: function(destination, source) {
if (source == '1') {
return new _uexpr_pf('--', destination);
}
return _assign(destination, new _bexpr('-', destination, source));
},
add: function(destination, source_a, source_b) {
if ((destination == source_a) && (source_b == '1')) {
return new _uexpr_pf('++', destination);
}
return _assign(destination, new _bexpr('+', source_a, source_b));
},
and: function(destination, source_a, source_b) {
if (source_b == '0') {
return _assign(destination, '0');
}
return _assign(destination, new _bexpr('&', source_a, source_b));
},
divide: function(destination, source_a, source_b) {
return _assign(destination, new _bexpr('/', source_a, source_b));
},
module: function(destination, source_a, source_b) {
return _assign(destination, new _bexpr('%', source_a, source_b));
},
multiply: function(destination, source_a, source_b) {
return _assign(destination, new _bexpr('*', source_a, source_b));
},
negate: function(destination, source) {
return _assign(destination, new _uexpr('-', source));
},
not: function(destination, source) {
return _assign(destination, new _uexpr('~', source));
},
extend: function(destination, source, bits) {
return _assign(destination, new _uexpr('(int' + bits + '_t) ', source));
},
subtract: function(destination, source_a, source_b) {
if ((destination == source_a) && (source_b == '0')) {
return null;
} else if (destination == source_a && source_b == '1') {
return new _uexpr_pf('--', destination);
}
return _assign(destination, new _bexpr('-', source_a, source_b));
},
or: function(destination, source_a, source_b) {
if (source_b == '0') {
return _assign(destination, source_a);
}
return _assign(destination, new _bexpr('|', source_a, source_b));
},
xor: function(destination, source_a, source_b) {
if (source_a == source_b) {
return _assign(destination, '0');
}
return _assign(destination, new _bexpr('^', source_a, source_b));
},
shift_left: function(destination, source_a, source_b) {
return _assign(destination, new _bexpr('<<', source_a, source_b));
},
shift_right: function(destination, source_a, source_b) {
return _assign(destination, new _bexpr('>>', source_a, source_b));
},
rotate_left: function(destination, source_a, source_b, bits) {
Global().context.addDependency(new CCalls.rotate_left.fcn(bits));
return new _generic_rotate(destination, source_a, source_b, bits, true);
},
rotate_right: function(destination, source_a, source_b, bits) {
Global().context.addDependency(new CCalls.rotate_right.fcn(bits));
return new _generic_rotate(destination, source_a, source_b, bits, false);
},
swap_endian: function(value, returns, bits) {
Global().context.addDependency(new CCalls.swap_endian.fcn(bits));
return _assign(returns, new _generic_call('SWAP' + bits, [value]));
},
swap: function(source_a, source_b, bits) {
var t = Variable.uniqueName('tmp');
var ops = [
_assign(Extra.to.type(bits, false) + ' ' + t, source_a),
_assign(source_a, source_b),
_assign(source_b, t),
];
return new function(composed) {
this.composed = composed;
}(ops);
},
bit_mask: function(destination, source_a, source_b) {
Global().context.addDependency(new CCalls.bit_mask.fcn());
return _assign(destination, new _generic_call('BIT_MASK', [source_a, source_b]));
},
/* MEMORY */
read_memory: function(pointer, register, bits, is_signed) {
var value = (Extra.is.string(register) || Extra.is.number(register)) ? Variable.local(register.toString(), Extra.to.type(bits, is_signed)) : register;
var ptr = (Extra.is.number(pointer) || Long.isLong(pointer)) ? Variable.pointer('0x' + pointer.toString(16), Extra.to.type(bits, is_signed)) : pointer;
if (Extra.is.string(ptr)) {
ptr = Variable.pointer(pointer, Extra.to.type(bits, is_signed));
}
return _assign(value, ptr);
},
write_memory: function(pointer, register, bits, is_signed) {
var value = (Extra.is.string(register) || Extra.is.number(register)) ? Variable.local(register.toString(), Extra.to.type(bits, is_signed)) : register;
var ptr = (Extra.is.number(pointer) || Long.isLong(pointer)) ? Variable.pointer('0x' + pointer.toString(16), Extra.to.type(bits, is_signed)) : pointer;
if (Extra.is.string(ptr)) {
ptr = Variable.pointer(pointer, Extra.to.type(bits, is_signed));
}
return _assign(ptr, value);
},
/* SPECIAL */
composed: function(instructions) {
return new function(composed) {
this.composed = composed;
}(instructions);
},
macro: function(macro, macro_rule) {
Global().context.addMacro(macro_rule);
return new function(macro) {
this.macro = macro;
this.toString = function() {
return Global().printer.theme.macro(this.macro);
};
}(macro);
},
special: function(data) {
return new function(data) {
this.data = data;
this.toString = function() {
return Global().printer.auto(this.data);
};
}(data);
},
/* Object based langs */
method_call: function(object_this, method_separator, function_name, function_arguments, prefix, postfix) {
return new _generic_method_call(object_this, function_name, function_arguments, method_separator, prefix, postfix);
},
objc_call: function(object_this, function_name, function_arguments) {
return new _generic_objc_call(object_this, function_name, function_arguments);
},
/* Object based langs */
assign_to_object_field: function(destination, object, method_separator, field) {
return new _assign_object_field(destination, object, field, method_separator, false);
},
assign_from_object_field: function(destination, object, method_separator, field) {
return new _assign_object_field(destination, object, field, method_separator, true);
},
assign_to_array: function(destination, source, index) {
return new _assign_array_at(destination, source, index, false);
},
assign_from_array: function(destination, source, index) {
return new _assign_array_at(destination, source, index, true);
},
throw: function(value) {
return new _generic_throw(value);
},
/* UNKNOWN */
unknown: function(asm) {
return new _generic_asm(asm);
}
};
+130
View File
@@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Long from '../long.js';
var Bounds = function(low, hi) {
this.low = low;
this.hi = hi;
this.gt = function(bound) {
return this.low.gt(bound.low);
};
this.isInside = function(addr) {
return addr ? (addr.gte(this.low) && addr.lte(this.hi)) : false;
};
this.isOutside = function(addr) {
return !this.isInside(addr);
};
};
Bounds.invalid = function() {
return new Bounds(Long.MAX_U64_VALUE, Long.MAX_U64_VALUE);
};
var _sort_extra = function(a, b) {
if (a.address.eq(b.address)) {
return 0;
}
return a.address.gt(b.address) ? 1 : -1;
};
var _fill_splitted_extra = function(oldblock, newblock, name) {
var e = oldblock[name][oldblock[name].length - 1];
while (e && e.address.gte(newblock.bounds.low)) {
newblock[name].push(oldblock[name].pop());
e = oldblock[name][oldblock[name].length - 1];
}
};
export default function _block(bounds) {
this.bounds = bounds || Bounds.invalid();
this.extraHead = [];
this.extraTail = [];
this.instructions = [];
this.addInstruction = function(instruction) {
this.instructions.push(instruction);
this.update();
};
this.addExtraHead = function(extra) {
this.extraHead.push(extra);
this.extraHead.sort(_sort_extra);
};
this.lastHead = function(extra) {
return this.extraHead.length > 0 ? this.extraHead[this.extraHead.length - 1] : null;
};
this.firstTail = function(extra) {
return this.extraTail.length > 0 ? this.extraTail[0] : null;
};
this.addExtraTail = function(extra) {
this.extraTail.unshift(extra);
this.extraTail.sort(_sort_extra);
};
this.update = function() {
var l = this.instructions.length;
if (l > 0) {
var first = this.instructions[0];
var last = this.instructions[l - 1];
this.bounds = new Bounds(first.location, last.location);
} else {
// invalidate this block if is empty..
this.bounds = Bounds.invalid();
}
};
this.split = function(from) {
if (from < 0 || from >= this.instructions.length) {
return null;
}
var i = this.instructions.splice(from, this.instructions.length);
var b = new _block(new Bounds(i[0].location, i[i.length - 1].location));
b.instructions = i;
_fill_splitted_extra(this, b, 'extraHead');
_fill_splitted_extra(this, b, 'extraTail');
this.update();
b.update();
return b;
};
this.ascomment = function() {
for (var i = 0; i < this.instructions.length; i++) {
this.instructions[i].ascomment();
}
};
this.ascodeline = function() {
for (var i = 0; i < this.instructions.length; i++) {
this.instructions[i].ascodeline();
}
};
this.hasPrintables = function() {
for (var i = 0; i < this.instructions.length; i++) {
if (this.instructions[i].valid && this.instructions[i].code) {
return true;
}
}
return false;
};
this.print = function() {
var h = 0;
var t = 0;
var i;
for (i = 0; i < this.instructions.length; i++) {
while (this.extraHead[h] && this.extraHead[h].address.lte(this.instructions[i].location)) {
this.extraHead[h].print();
h++;
}
this.instructions[i].print();
while (this.extraTail[t] && this.extraTail[t].address.eq(this.instructions[i].location)) {
this.extraTail[t].print();
t++;
}
}
//this one is bad, but it still require to be executed.
for (i = h; i < this.extraHead.length; i++) {
this.extraHead[i].print();
}
//this one is ok.
for (i = t; i < this.extraTail.length; i++) {
this.extraTail[i].print();
}
};
}
+19
View File
@@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2019-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
/*
* Expects the icj json as input.
*/
export default function(icj) {
var data = {};
icj.forEach(function(x) {
data[x.addr.toString()] = x.classname;
});
this.data = data;
this.search = function(address) {
if (address) {
return this.data[address.toString()];
}
return null;
};
}
+42
View File
@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Extra from './extra.js';
const _cmps = {
CUST: ['', ''],
INF: ['1', '0'],
EQ: [' == ', ' != '],
NE: [' != ', ' == '],
LT: [' < ', ' >= '],
LE: [' <= ', ' > '],
GT: [' > ', ' <= '],
GE: [' >= ', ' < '],
LO: [' overflow ', ' !overflow '],
NO: [' !overflow ', ' overflow '],
INSTANCEOF: [' instanceof ', null],
};
export default {
inf: function() {
this.toString = function() {
return Global().printer.theme.integers('1');
};
},
convert: function(a, b, cond, invert) {
this.invert = invert;
this.condition = cond; // ? _cmps[cond][invert ? 1 : 0] : '';
this.a = a;
this.b = b || '';
/* main method */
this.toString = function() {
var a = Extra.is.string(this.a) ? Global().printer.auto(this.a) : this.a;
var b = Extra.is.string(this.b) ? Global().printer.auto(this.b) : this.b;
if (this.invert && _cmps[this.condition][1]) {
return a + _cmps[this.condition][1] + b;
} else if (this.invert) {
return '!(' + a + Global().printer.theme.flow(_cmps[this.condition][0]) + b + ')';
}
return a + _cmps[this.condition][0] + b;
};
},
};
+333
View File
@@ -0,0 +1,333 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Base from './base.js';
import Utils from './utils.js';
import Scope from './scope.js';
import Variable from './variable.js';
import Condition from './condition.js';
var _compare_locations = function(a, b) {
if (a.eq(b.location)) {
return 0;
}
return a.lt(b.location) ? 1 : -1;
};
var _compare_blocks = function(a, b) {
if (a == b) {
return 0;
}
return a.bounds.gt(b.bounds) ? 1 : -1;
};
var _condition = function(instruction, invert) {
return instruction.cond ? new Condition.convert(instruction.cond.a, instruction.cond.b, instruction.cond.type, invert) : new Condition.inf();
};
var ControlFlowContext = function(blocks, instructions) {
this.instructions = instructions;
this.labels = [];
this.addLabel = function(label) {
if (label) {
this.labels.push(label);
}
};
this.findLabel = function(location) {
for (var i = 0; i < this.labels.length; i++) {
if (this.labels[i].address.eq(location)) {
return this.labels[i];
}
}
};
this.blocks = blocks;
this.addBlock = function(blk) {
if (blk) {
this.blocks.push(blk);
this.blocks = this.blocks.sort(_compare_blocks);
}
};
this.findBlock = function(location) {
for (var i = 0; i < this.blocks.length; i++) {
if (this.blocks[i].bounds.isInside(location)) {
return this.blocks[i];
}
}
};
};
var _set_goto = function(instruction, label) {
if (!instruction.code || !instruction.valid) {
instruction.code = Base.goto(label);
instruction.valid = true;
} else if (instruction.code.composed) {
instruction.code.composed.push(Base.goto(label));
} else {
instruction.code = Base.composed([instruction.code, Base.goto(label)]);
}
};
var _set_outbounds_jump = function(instruction, index, context) {
if (Utils.search(instruction.jump, context.instructions, _compare_locations) && context.findBlock(instruction.location)) {
return false;
}
if (!instruction.code) {
//instruction.code = Base.goto('0x' + instruction.jump.toString());
var call = Variable.functionPointer('0x' + instruction.jump.toString(16), 0, []);
instruction.code = Base.call(call, []);
// if we have a jump as the last instruction, then we will have a return call for sure.
}
if (context.instructions.indexOf(instruction) == (context.instructions.length - 1)) {
instruction.code = Base.return(instruction.code);
if (instruction.cond) {
instruction.comments.push('Beware that this jump is a conditional jump.');
instruction.comments.push('jsdec transformed it as a return, due being the');
instruction.comments.push('last instruction. Please, check \'pdda\' output');
instruction.comments.push('for more hints.');
}
} else if (instruction.cond) {
var block = context.findBlock(instruction.location);
if (block) {
var single_instr = block.split(block.instructions.indexOf(instruction));
if (single_instr) {
single_instr.addExtraHead(new Scope.if(instruction.location, _condition(instruction, false)));
single_instr.addExtraTail(new Scope.brace(instruction.location));
context.addBlock(single_instr);
context.addBlock(single_instr.split(1));
}
}
}
instruction.setBadJump();
return true;
};
var _set_loops = function(instruction, index, context) {
// loops jumps only backwards or to the same location.
var single_instr = null;
if (instruction.jump.gt(instruction.location)) {
return false;
}
var block = context.findBlock(instruction.location);
if (!block) {
return false;
}
// let's check if is a oneline loop or panic loop
if (instruction.jump.eq(instruction.location)) {
single_instr = block.split(index);
if (single_instr) {
if (!instruction.code) {
single_instr.addExtraHead(new Scope.whileInline(instruction.jump, _condition(instruction)));
} else {
single_instr.addExtraHead(new Scope.do(instruction.jump));
single_instr.addExtraTail(new Scope.whileEnd(instruction.location, _condition(instruction)));
}
context.addBlock(single_instr);
context.addBlock(single_instr.split(1));
}
return true;
}
var loop_start = Utils.search(instruction.jump, block.instructions, _compare_locations);
if (!loop_start) {
var label = context.findLabel(instruction.jump);
if (!label) {
label = Variable.newLabel(instruction.jump);
context.addLabel(label);
}
_set_goto(instruction, label);
if (instruction.cond) {
single_instr = block.split(block.instructions.indexOf(instruction));
// here the jump is taken only if the condition is true.
if (single_instr) {
single_instr.addExtraHead(new Scope.if(instruction.location, _condition(instruction, false)));
single_instr.addExtraTail(new Scope.brace(instruction.location));
context.addBlock(single_instr);
context.addBlock(single_instr.split(1));
}
}
return true;
}
var loop_start_index = block.instructions.indexOf(loop_start);
var previous = block.instructions[loop_start_index - 1];
var loop_block = block.split(loop_start_index);
var next = loop_block.split(loop_block.instructions.indexOf(instruction) + 1);
// let's check it there is a jump inside the loop
// if it is, then it's a while (cond) {}
if (previous && previous.jump && previous.jump.gte(instruction.jump) && previous.jump.lte(instruction.location)) {
previous.setBadJump();
loop_block.addExtraHead(new Scope.while(instruction.jump, _condition(instruction)));
loop_block.addExtraTail(new Scope.brace(instruction.location));
} else {
// ok it's a do {} while (cond);
loop_block.addExtraHead(new Scope.do(instruction.jump));
loop_block.addExtraTail(new Scope.whileEnd(instruction.location, _condition(instruction)));
}
context.addBlock(loop_block);
context.addBlock(next);
return true;
};
var _set_if_else = function(instruction, index, context) {
var label = null;
// if/else jumps only forward and inside the block.
if (instruction.jump.lte(instruction.location)) {
return false;
}
// if jumps to the next instruction, just ignore it..
if (!instruction.cond && context.instructions[index + 1] && context.instructions[index + 1].location.eq(instruction.jump)) {
instruction.setBadJump();
return false;
}
if (!instruction.cond) {
if (!instruction.code) {
label = context.findLabel(instruction.jump);
if (!label) {
label = Variable.newLabel(instruction.jump);
context.addLabel(label);
}
instruction.code = Base.goto(label);
} else if (instruction.code.composed) {
label = context.findLabel(instruction.jump);
if (!label) {
label = Variable.newLabel(instruction.jump);
context.addLabel(label);
}
instruction.code.composed.push(Base.goto(label));
}
return true;
}
var block = context.findBlock(instruction.location);
if (!block) {
return false;
}
var outside = Utils.search(instruction.jump, block.instructions, _compare_locations);
// not found. let's use goto.
if (!outside) {
label = context.findLabel(instruction.jump);
if (!label) {
label = Variable.newLabel(instruction.jump);
context.addLabel(label);
}
_set_goto(instruction, label);
if (instruction.cond) {
var single_instr = block.split(block.instructions.indexOf(instruction));
if (!single_instr) {
return true;
}
// here the jump is taken only if the condition is true.
single_instr.addExtraHead(new Scope.if(instruction.location, _condition(instruction, false)));
single_instr.addExtraTail(new Scope.brace(instruction.location));
context.addBlock(single_instr);
context.addBlock(single_instr.split(1));
}
return true;
}
// let's create the if block.
var if_block = block.split(block.instructions.indexOf(instruction));
if (!if_block) {
return false;
}
if_block.addExtraHead(new Scope.if(instruction.location, _condition(instruction, true)));
// let's get the last element inside the if (jump instr -1).
var outside_index = if_block.instructions.indexOf(outside);
var last_if_instruction = if_block.instructions[outside_index - 1];
if (!last_if_instruction) {
return true;
}
// let's check if the last instruction is a jump forward (outside), that can lead to an else
if (last_if_instruction.jump && !last_if_instruction.cond && last_if_instruction.jump.gt(last_if_instruction.location)) {
// ok we have an else. let's search for the last instruction.
var first_else_instruction = outside;
var instr_after_else = Utils.search(last_if_instruction.jump, context.instructions, _compare_locations);
var last_else_instruction = context.instructions[context.instructions.indexOf(instr_after_else) - 1];
if (Utils.search(last_else_instruction.location, if_block.instructions, _compare_locations) && first_else_instruction != instr_after_else) {
var lh = if_block.lastHead();
var ft = if_block.firstTail();
if (lh && lh.isElse && ft && ft.address.eq(last_else_instruction.location)) {
if_block.addExtraTail(new Scope.brace(first_else_instruction.location));
if_block.addExtraHead(new Scope.else(first_else_instruction.location));
} else {
if_block.addExtraHead(new Scope.else(first_else_instruction.location));
if_block.addExtraTail(new Scope.brace(last_else_instruction.location));
}
last_if_instruction.setBadJump();
outside_index = if_block.instructions.indexOf(last_else_instruction) + 1;
} else {
if_block.addExtraTail(new Scope.brace(last_if_instruction.location));
}
} else {
if_block.addExtraTail(new Scope.brace(last_if_instruction.location));
}
context.addBlock(if_block);
context.addBlock(if_block.split(outside_index));
return true;
};
var _set_custom_flow = function(instruction, index, context) {
var block = context.findBlock(instruction.location);
if (!block) {
return false;
}
var first_external_instruction = Utils.search(instruction.jump, block.instructions, _compare_locations);
var if_block = block.split(block.instructions.indexOf(instruction));
if (!if_block) {
return false;
}
var first_external_instruction_index = if_block.instructions.indexOf(first_external_instruction);
if_block.addExtraHead(new Scope.custom(instruction.location, instruction.customflow));
if_block.addExtraTail(new Scope.brace(first_external_instruction.location));
context.addBlock(if_block);
context.addBlock(if_block.split(first_external_instruction_index));
return true;
};
export default function(session) {
var j, i;
var context = new ControlFlowContext(session.blocks, session.instructions);
for (j = 0; j < session.instructions.length; j++) {
if (!session.instructions[j].jump || !session.instructions[j].customflow) {
continue;
}
_set_custom_flow(session.instructions[j], j, context);
}
for (j = 0; j < session.instructions.length; j++) {
if (!session.instructions[j].jump || session.instructions[j].customflow) {
continue;
}
if (!_set_outbounds_jump(session.instructions[j], j, context)) {
_set_loops(session.instructions[j], j, context);
}
}
for (j = 0; j < session.instructions.length; j++) {
if (!session.instructions[j].jump || session.instructions[j].customflow) {
continue;
}
_set_if_else(session.instructions[j], j, context);
}
for (i = 0; i < context.labels.length; i++) {
var instruction = Utils.search(context.labels[i].address, session.instructions, _compare_locations);
instruction.label = context.labels[i];
}
session.blocks = context.blocks.sort(_compare_blocks);
}
+227
View File
@@ -0,0 +1,227 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import _call_common from '../db/macros.js';
import Long from '../long.js';
/**
* Types size
* @type {Object}
*/
const _standard_types = {
'void': 0,
'char': 8,
'short': 16,
'long': 32,
'float': 32,
'long long': 64,
'double': 64,
};
const _magic_math_values = {
"0x069c16bd": 'if there is a right shift of 0, then it\'s a division by 665/25756',
"0x10624dd3": 'if there is a right shift of 4, then it\'s a division by 1/250',
"0x2aaaaaab": 'if there is a right shift of 0, then it\'s a division by 1/6',
"0x30c30c31": 'if there is a right shift of 3, then it\'s a division by 1/42',
"0x38e38e39": 'if there is a right shift of 1, then it\'s a division by 1/9',
"0x4ec4ec4f": 'if there is a right shift of 3, then it\'s a division by 1/26',
"0x51eb851f": 'if there is a right shift of 5, then it\'s a division by 1/100',
"0x55555556": 'if there is a right shift of 0, then it\'s a division by 1/3',
"0x66666667": 'if there is a right shift of 1, then it\'s a division by 1/5',
"0x6bca1af3": 'if there is a right shift of 5, then it\'s a division by 1/76',
"0x88888889": 'if there is a right shift of 8, then it\'s a division by 1/480',
"0x92492493": 'if there is a right shift of 3, then it\'s a division by 1/14',
"0xa0a0a0a1": 'if there is a right shift of 7, then it\'s a division by 1/204',
"0xaaaaaaab": 'if there is a right shift of 1, then it\'s a division by 1/3',
"0xae147ae1": 'if there is a right shift of 5, then it\'s a division by 17/800',
"0xb21642c9": 'if there is a right shift of 5, then it\'s a division by 1/46',
"0xb60b60b7": 'if there is a right shift of 5, then it\'s a division by 1/45',
"0xba2e8ba3": 'if there is a right shift of 3, then it\'s a division by 1/11',
"0xea0ea0eb": 'if there is a right shift of 0, then it\'s a division by 32/35',
};
var _align_address = function(x) {
var zeros32 = '00000000';
var c = x.toString(16);
if (c.length > zeros32.length) {
return '0x' + c;
}
return '0x' + zeros32.substr(c.length, zeros32.length) + c;
};
/**
* Is helpers
* @type {Object}
*/
const _is = {
string: function(s) {
return typeof s == 'string';
},
number: function(s) {
return typeof s == 'number';
},
array: function(s) {
return Array.isArray(s);
},
inObject: function(object, value) {
for (var k in object) {
if (object[k] == value) {
return true;
}
}
return false;
},
};
/**
* To helpers
* @type {Object}
*/
const _to = {
type: function(bits, signed) {
if (bits == 0 || !bits) {
return 'void';
}
return (signed ? 'int' : 'uint') + bits + '_t';
},
bits: function(type) {
var bits = Global().evars.archbits;
type = type.replace(/[un]?signed\s?/, '');
if (type.length == 0) {
type = bits < 32 ? 'int16_t' : 'int32_t';
}
if (_standard_types[type]) {
return _standard_types[type];
}
if (type == 'int') {
return bits < 32 ? 16 : 32;
}
return parseInt(type.replace(/[intu_]/g, ''));
},
array: function(object) {
var a = [];
for (var key in object) {
a.push(object[key]);
}
return a;
},
};
/**
* Find helpers
* @type {Object}
*/
const _find = {
arguments_number: function(name) {
name = _replace.call(name);
if (_call_common[name]) {
return _call_common[name].required;
} else if (Global().argdb) {
var db = Global().argdb;
for (var k in db) {
if (_replace.call(db[k].name.replace(/^_+/, '')) == name) {
if (db[k].count) {
return parseInt(db[k].count.toString());
}
return db[k].args.length;
}
}
}
return -1;
},
call_additional: function(name) {
name = _replace.call(name);
if (_call_common[name]) {
return !!_call_common[name].varargs;
}
return false;
}
};
/**
* Replace helpers
* @type {Object}
*/
const _replace = {
call: function(name) {
if (typeof name != 'string' || name.startsWith('0x')) {
return name;
}
if (name.startsWith('sym.imp.')) {
name = name.substring('sym.imp.'.length).replace(/^_+/, '');
} else if (name.startsWith('sym.')) {
name = name.substring('sym.'.length).replace(/^_+/, '');
} else if (name.startsWith('imp.')) {
name = name.substring('imp.'.length).replace(/^_+/, '');
//} else if (name.startsWith('fcn.')) {
// name = name.substring('fcn.'.length);
//} else if (name.startsWith('func.')) {
// name = name.substring('func.'.length);
}
if (name.startsWith('reloc.')) {
name = name.substring('reloc.'.length).replace(/^_+/, '');
}
name = name.replace(/^sub\./, '');
if (name.match(/^[\w]+\.dll_/)) {
name = name.replace(/[\w]+\.dll_/, '');
}
name = name.replace(/[Mm][Ss][Vv][Cc][Rr][Tt]\.[Dd][Ll][Ll]_/, '');
name = name.replace(/\./g, '_');
return name.replace(/(\w|^):(\w|$)/g, '$1_$2').replace(/_+/g, '_');
},
object: function(name) {
if (typeof name != 'string' || name.startsWith('0x')) {
return name;
}
if (name.startsWith('sym.imp.')) {
name = name.substring('sym.imp.'.length);
} else if (name.startsWith('sym.')) {
name = name.substring('sym.'.length);
} else if (name.startsWith('imp.')) {
name = name.substring('imp.'.length);
//} else if (name.startsWith('fcn.')) {
// name = name.substring('fcn.'.length);
//} else if (name.startsWith('func.')) {
// name = name.substring('func.'.length);
} else if (name.startsWith('reloc.')) {
name = name.substring('reloc.'.length);
}
if (name.startsWith('L') || name.startsWith('[L')) {
// java object
name = name.replace(/\.<init>\(.+$|\(.+$|\._init_.+V$|_L.+$/, '');
name = name.substr(name.startsWith('L') ? 1 : 2).replace(/\/|;->/g, '.').replace(/\s.+$|;$/, '');
if (name.indexOf('_L') > 0) {
name = name.substring(0, name.indexOf('_L'));
}
}
return name;
}
};
const _tryas = {
int: function(x) {
try {
return Long.from(x.trim(), false, (x.trim().indexOf('0x') == 0 ? 16 : 10));
} catch (e) {}
return x;
}
};
/**
* Extra object
* @return {Function} - Extra object
*/
export default {
tryas: _tryas,
is: _is,
to: _to,
find: _find,
replace: _replace,
align_address: _align_address,
magic_math: function(address) {
if (typeof address != 'string') {
address = '0x' + address.toString(16);
}
return _magic_math_values[address];
}
};
+51
View File
@@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import rzpipe from '../rzpipe.js';
import Utils from './utils.js';
var _compare_search = function(a, b) {
if (a.eq(b.offset)) {
return 0;
} else if (a.lt(b.offset)) {
return 1;
}
return -1;
};
var _compare_offsets = function(a, b) {
return a.offset.lt(b.offset) ? -1 : (a.offset.eq(b.offset) ? 0 : 1);
};
var _compare_name = function(a, b) {
return a.name < b.name ? -1 : (a.name == b.name ? 0 : 1);
};
var create_fcn_data = function(x) {
if (!x) {
return null;
}
return {
offset: x.offset,
name: x.name,
calltype: x.calltype,
nargs: x.nargs
};
};
/*
* Expects the aflj json as input.
*/
export default function(aflj, sort_by_name) {
this.data = aflj.sort(sort_by_name ? _compare_name : _compare_offsets).map(function(x) {
return create_fcn_data(x);
});
this.search = function(offset) {
if (!Global().evars.extra.slow && offset) {
var x = rzpipe.json('afij @ 0x' + offset.toString(16), [])[0];
return create_fcn_data(x);
}
return offset ? Utils.search(offset, this.data, _compare_search) : null;
};
}
+178
View File
@@ -0,0 +1,178 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Condition from './condition.js';
import Extra from './extra.js';
import Long from '../long.js';
var _printable = function(instr) {
return instr.valid && instr.code && instr.code.toString().length > 0;
};
var _conditional = function(cond) {
return (new Condition.convert(cond.a, cond.b, cond.type, false)).toString();
};
var _asm_rizin_view = function(instr, ascodeline) {
var s = '';
if (instr.label) {
s = instr.label.name + ":\n";
}
if (instr.code && instr.code.composed) {
if (instr.cond && instr.jump) {
s += (instr.jump.gt(instr.location) ? "if" : "while") + " (" + _conditional(instr.cond) + ") {\n";
}
for (var i = 0; i < instr.code.composed.length; i++) {
s += instr.code.composed[i] + '\n';
}
if (instr.cond && instr.jump) {
s += "}\n";
}
} else if (_printable(instr)) {
if (instr.cond && instr.jump) {
s += "if (" + _conditional(instr.cond) + ") " + instr.code + "\n";
} else {
s += instr.code + "\n";
}
} else if (instr.cond && !_printable(instr) && instr.jump) {
s += "if (" + _conditional(instr.cond) + ") goto 0x" + instr.jump.toString(16);
}
if (ascodeline) {
Global().evars.add_code_line(s.trim(), instr.location);
} else {
Global().evars.add_comment(s.trim(), instr.location);
}
};
var _asm_view = function(instr) {
var i, t, b, s, addr;
if (Global().evars.honor.blocks) {
return;
}
if (Global().evars.honor.offsets) {
t = Global().printer.theme;
addr = Extra.align_address(instr.location);
if (instr.code && instr.code.composed) {
Global().context.printLine(Global().context.identfy(addr.length, t.integers(addr)) + instr.code.composed[0] + ';', instr.location);
for (i = 1; i < instr.code.composed.length; i++) {
Global().context.printLine(Global().context.identfy(addr.length, t.integers(addr)) + instr.code.composed[i] + ';', instr.location);
}
} else if (_printable(instr)) {
Global().context.printLine(Global().context.identfy(addr.length, t.integers(addr)) + instr.code + ';', instr.location);
}
} else if (Global().evars.honor.assembly) {
t = Global().printer.theme;
b = Global().printer.auto;
addr = Extra.align_address(instr.location);
s = 1 + addr.length + instr.simplified.length;
if (instr.code && instr.code.composed) {
Global().context.printLine(Global().context.identfy(s, t.integers(addr) + ' ' + b(instr.simplified)) + instr.code.composed[0] + ';', instr.location);
for (i = 1; i < instr.code.composed.length; i++) {
Global().context.printLine(Global().context.identfy() + instr.code.composed[i] + ';', instr.location);
}
} else {
Global().context.printLine(Global().context.identfy(s, t.integers(addr) + ' ' + b(instr.simplified)) + (_printable(instr) ? (instr.code + ';') : ''), instr.location);
}
} else {
if (instr.code && instr.code.composed) {
for (i = 0; i < instr.code.composed.length; i++) {
Global().context.printLine(Global().context.identfy() + instr.code.composed[i] + ';', instr.location);
}
} else if (_printable(instr)) {
Global().context.printLine(Global().context.identfy() + instr.code + ';', instr.location);
}
}
};
var _instruction = function(data, arch, marker) {
this.code = null;
this.marker = marker;
this.valid = true;
this.jump = data.jump ? Long.from(data.jump, true) : null;
this.type = data.type;
this.pointer = (data.ptr && Long.ZERO.lt(data.ptr)) ? data.ptr : null;
this.location = Long.from(data.offset, true);
this.assembly = data.disasm || data.opcode;
this.simplified = data.opcode;
this.cpp_type = this.assembly.match(/(class|method|struct)\s[\w:]+(<[\w:<, >]+>)?\s+/);
if (this.cpp_type) {
this.assembly = this.assembly.replace(this.cpp_type[0], '');
}
this.parsed = arch.parse(this.assembly, this.simplified);
this.string = null;
this.symbol = null;
this.klass = null;
this.callee = null;
this.label = null;
this.cond = null;
this.customflow = null;
this.xrefs = data.xrefs ? data.xrefs.slice() : [];
this.refs = data.refs ? data.refs.slice() : [];
this.comments = data.comment ? [data.comment] : [];
if (Global().evars.honor.xrefs) {
for (var i = 0; i < this.xrefs.length; i++) {
var e = 'XREF ' + this.xrefs[i].type + ": 0x" + this.xrefs[i].addr.toString(16);
this.comments.push(e);
}
}
this.conditional = function(a, b, type) {
if (type) {
this.cond = {
a: a,
b: b,
type: type
};
}
};
this.setBadJump = function() {
this.jump = null;
};
this.print = function() {
var t = Global().printer.theme;
var empty = Global().context.identfy();
if (this.comments.length == 1) {
Global().context.printLine(empty + t.comment('/* ' + this.comments[0] + ' */'), this.location);
} else if (this.comments.length > 1) {
Global().context.printLine(empty + t.comment('/* ' + this.comments[0]), this.location);
for (var i = 1; i < this.comments.length; i++) {
var comment = ' * ' + this.comments[i] + (i == this.comments.length - 1 ? ' */' : '');
Global().context.printLine(empty + t.comment(comment), this.location);
}
}
if (this.label) {
Global().context.printLine(Global().context.identfy(null, null, true) + this.label + ':', this.location);
}
_asm_view(this);
};
this.ascomment = function() {
_asm_rizin_view(this, false);
};
this.ascodeline = function() {
_asm_rizin_view(this, true);
};
};
_instruction.swap = function(instructions, index_a, index_b) {
var a = instructions[index_a];
var b = instructions[index_b];
instructions[index_b] = a;
instructions[index_a] = b;
var a_loc = a.location;
a.location = b.location;
b.location = a_loc;
if (a.jump && b.location.eq(a.jump)) {
a.jump = a.location;
} else if (b.jump && a.location.eq(b.jump)) {
b.jump = b.location;
}
};
export default _instruction;
+12
View File
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
export default function(data) {
this.data = data;
this.print = function() {
var t = Global().printer.theme;
for (var i = 0; i < this.data.length; i++) {
Global().context.printLine(Global().context.identfy() + t.macro(this.data[i]));
}
};
}
+290
View File
@@ -0,0 +1,290 @@
// SPDX-FileCopyrightText: 2019-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Extra from './extra.js';
import Base from './base.js';
const _x86_stret = {
'32': {
returns: 'rdi',
receiver: 'eax',
selector: 'ecx',
args: ['edx', 'ecx', 'r8d', 'r9d']
},
'64': {
returns: 'rdi',
receiver: 'rsi',
selector: 'rdx',
args: ['rcx', 'r8', 'r9', 'r10']
}
};
const _x86 = {
'32': {
receiver: 'eax',
selector: 'ecx',
returns: 'eax',
args: ['edx', 'ecx', 'r8d', 'r9d']
},
'64': {
receiver: 'rdi',
selector: 'rsi',
returns: 'rax',
args: [
['edx', 'rdx'],
['ecx', 'rcx'],
['r8d', 'r8'],
['r9d', 'r9']
]
}
};
const _ppc = {
receiver: 'r3',
selector: 'r4',
returns: 'r3',
args: ['r5', 'r6', 'r7', 'r8']
};
const _ppc_stret = {
returns: 'r3',
receiver: 'r4',
selector: 'r5',
args: ['r6', 'r7', 'r8', 'r9']
};
const _arm = {
'16': {
receiver: 'r0',
selector: 'r1',
returns: 'r0',
args: ['r2', 'r3', 'r4', 'r5']
},
'32': {
receiver: 'r0',
selector: 'r1',
returns: 'r0',
args: ['r2', 'r3', 'r4', 'r5']
},
'64': {
receiver: 'x0',
selector: 'x1',
returns: 'x0',
args: ['x2', 'x3', 'x4', 'x5']
}
};
const _arm_stret = {
'16': {
receiver: 'r1',
selector: 'r2',
returns: 'r0',
args: ['r3', 'r4', 'r5', 'r6']
},
'32': {
receiver: 'r1',
selector: 'r2',
returns: 'r0',
args: ['r3', 'r4', 'r5', 'r6']
}
};
const _object_c_registers = {
'x86': {
'32': ['rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9'],
'64': ['edi', 'esi', 'edx', 'ecx', 'r8d', 'r9d'],
},
'ppc': {
'32': ['r3', 'r4', 'r5', 'r6', 'r7', 'r8'],
'64': ['r3', 'r4', 'r5', 'r6', 'r7', 'r8'],
},
'arm': {
'16': ['r0', 'r1', 'r2', 'r3', 'r4', 'r5'],
'32': ['r0', 'r1', 'r2', 'r3', 'r4', 'r5'],
'64': ['x0', 'x1', 'x2', 'x3', 'x4', 'x5'],
}
};
const _object_c_class_methods = {
objc_msgSend: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_fpret: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_noarg: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSendSuper: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSendSuper2: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_stret: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
objc_msgSendSuper_stret: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
objc_msgSendSuper2_stret: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
/* fixup */
objc_msgSend_fixup: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_fpret_fixup: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSendSuper2_fixup: {
'x86': _x86,
'ppc': {
'32': _ppc,
'64': _ppc
},
'arm': _arm
},
objc_msgSend_stret_fixup: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
},
objc_msgSendSuper2_stret_fixup: {
'x86': _x86_stret,
'ppc': {
'32': _ppc_stret,
'64': _ppc_stret
},
'arm': _arm_stret
}
};
const _object_c_block_methods = {
objc_autoreleasePoolPush: function(instr, context, instructions) {
if (!context.object_c.autorelease) {
context.object_c.autorelease = [instr];
} else {
context.object_c.autorelease.push(instr);
}
instr.customflow = '@' + Global().printer.theme.flow('autoreleasepool');
return Base.nop();
},
objc_autoreleasePoolPop: function(instr, context, instructions) {
context.object_c.autorelease.pop().jump = instr.location;
return Base.nop();
},
objc_retainAutoreleasedReturnValue: function() {
return Base.nop();
},
objc_release: function() {
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return Base.objc_call(_object_c_registers[arch][bits][0], 'release');
},
objc_retain: function() {
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return Base.objc_call(_object_c_registers[arch][bits][0], 'retain');
},
};
export default {
arguments: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].args.slice();
},
returns: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].returns;
},
receiver: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].receiver;
},
selector: function(callname) {
callname = Extra.replace.call(callname);
var arch = Global().evars.arch;
var bits = Global().evars.archbits.toString();
return _object_c_class_methods[callname][arch][bits].selector;
},
handle_others: function(callname, instr, context, instructions) {
if (_object_c_block_methods[callname]) {
if (!context.object_c) {
context.object_c = {};
}
return _object_c_block_methods[callname](instr, context, instructions);
}
return null;
},
is_class_method: function(callname) {
callname = Extra.replace.call(callname);
return !!_object_c_class_methods[callname];
},
is: function(callname) {
callname = Extra.replace.call(callname);
return callname.startsWith('objc_') && (
_object_c_block_methods[callname] ||
_object_c_class_methods[callname]
);
}
};
+53
View File
@@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: 2019-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Extra from './extra.js';
const _java = {
array: function(type, size, create, init) {
this.size = size || 0;
this.type = Extra.replace.object(type);
this.init = init;
this.toString = function() {
var t = [Global().printer.theme.flow('new'), Global().printer.theme.callname(this.type), '[' + this.size + ']'];
if (this.init && this.init.length > 0) {
t.push('{' + this.init.join(', ') + '}');
}
return t.join(' ');
};
},
object: function(type, args, create) {
this.args = args || [];
this.type = Extra.replace.object(type);
this.create = create || false;
this.toString = function() {
var a = this.args.length > 0 ? '(' + this.args.join(', ') + ')' : '';
if (this.create) {
return [Global().printer.theme.flow('new'), Global().printer.theme.callname(this.type), a].join(' ').trim();
}
return [Global().printer.theme.callname(this.type), a].join(' ').trim();
};
}
};
const _all_langs = {
java: _java,
dalvik: _java,
};
export default {
array: function(type, size, create, lang, init) {
lang = lang || Global().evars.arch;
if (!_all_langs[lang]) {
throw new Error('Missing lang for array (objects.js)');
}
return new _all_langs[lang].array(type, size, create, init || []);
},
object: function(type, args, create, lang) {
lang = lang || Global().evars.arch;
if (!_all_langs[lang]) {
throw new Error('Missing lang for object (objects.js)');
}
return new _all_langs[lang].object(type, args, create);
}
};
+167
View File
@@ -0,0 +1,167 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Extra from './extra.js';
var __debug = false;
function _print_locals(locals, address, spaced) {
if (Global().evars.honor.blocks) {
return;
}
var a = Global().printer.auto;
for (var i = 0; i < locals.length; i++) {
var local = Extra.is.string(locals[i]) ? a(locals[i]) : locals[i].toString(true);
Global().context.printLine(Global().context.identfy() + local + ';', address);
}
if (spaced && locals.length > 0) {
Global().context.printLine(Global().context.identfy(), address);
}
}
function _print_block_data(block) {
if (Global().evars.honor.blocks) {
var t = Global().printer.theme;
var ident = Global().context.identfy();
var addr = block.address.toString(16);
Global().context.printLine(ident + t.comment('/* address 0x' + addr + ' */'), block.address);
}
}
export default {
brace: function(address) {
this.address = address;
this.toString = function() {
return '}' + (__debug ? Global().printer.theme.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
Global().context.identOut();
var offset = Global().evars.honor.offsets ? Extra.align_address(this.address) : '';
Global().context.printLine(Global().context.identfy(offset.length, Global().printer.theme.integers(offset)) + this.toString(), this.address);
};
},
custom: function(address, colorname) {
this.address = address;
this.colorname = colorname;
this.toString = function() {
return this.colorname + ' {' + (__debug ? Global().printer.theme.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
var offset = Global().evars.honor.offsets ? Extra.align_address(this.address) : '';
Global().context.printLine(Global().context.identfy(offset.length, Global().printer.theme.integers(offset)) + this.toString(), this.address);
Global().context.identIn();
_print_block_data(this);
};
},
routine: function(address, extra) {
this.address = address;
this.extra = extra;
this.toString = function() {
var e = this.extra;
var t = Global().printer.theme;
var a = Global().printer.auto;
return t.types(e.returns) + ' ' + t.callname(e.routine_name) + ' (' + e.args.map(function(x) {
return Extra.is.string(x) ? a(x) : x.toString(true);
}).join(', ') + ') {' + (__debug ? t.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
var e = this.extra;
var t = Global().printer.theme;
_print_locals(e.globals, this.address, true);
var asmname = Global().evars.honor.offsets ? Extra.align_address(this.address) : '; (fcn) ' + e.name + ' ()';
var color = Global().evars.honor.offsets ? 'integers' : 'comment';
var ident = Global().context.identfy(asmname.length, t[color](asmname));
Global().context.printLine(ident + this.toString(), this.address);
Global().context.identIn();
_print_block_data(this);
_print_locals(e.locals, this.address);
};
},
if: function(address, condition, locals) {
this.address = address;
this.condition = condition;
this.locals = locals || [];
this.toString = function() {
var t = Global().printer.theme;
return t.flow('if') + ' (' + this.condition + ') {' + (__debug ? t.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
var offset = Global().evars.honor.offsets ? Extra.align_address(this.address) : '';
Global().context.printLine(Global().context.identfy(offset.length, Global().printer.theme.integers(offset)) + this.toString(), this.address);
Global().context.identIn();
_print_block_data(this);
_print_locals(this.locals, this.address);
};
},
else: function(address, locals) {
this.isElse = true;
this.address = address;
this.locals = locals || [];
this.toString = function() {
var t = Global().printer.theme;
return '} ' + t.flow('else') + ' {' + (__debug ? t.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
Global().context.identOut();
var offset = Global().evars.honor.offsets ? Extra.align_address(this.address) : '';
Global().context.printLine(Global().context.identfy(offset.length, Global().printer.theme.integers(offset)) + this.toString(), this.address);
Global().context.identIn();
_print_block_data(this);
_print_locals(this.locals, this.address);
};
},
do: function(address, locals) {
this.address = address;
this.locals = locals || [];
this.toString = function() {
var t = Global().printer.theme;
return t.flow('do') + ' {' + (__debug ? t.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
Global().context.printLine(Global().context.identfy() + this.toString(), this.address);
Global().context.identIn();
_print_block_data(this);
_print_locals(this.locals, this.address);
};
},
while: function(address, condition, locals) {
this.address = address;
this.condition = condition;
this.locals = locals || [];
this.toString = function() {
var t = Global().printer.theme;
return t.flow('while') + ' (' + this.condition + ') {' + (__debug ? t.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
var offset = Global().evars.honor.offsets ? Extra.align_address(this.address) : '';
Global().context.printLine(Global().context.identfy(offset.length, Global().printer.theme.integers(offset)) + this.toString(), this.address);
Global().context.identIn();
_print_block_data(this);
_print_locals(this.locals, this.address);
};
},
whileEnd: function(address, condition) {
this.address = address;
this.condition = condition;
this.toString = function() {
var t = Global().printer.theme;
return '} ' + t.flow('while') + ' (' + this.condition + ');' + (__debug ? t.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
Global().context.identOut();
Global().context.printLine(Global().context.identfy() + this.toString(), this.address);
};
},
whileInline: function(address, condition) {
this.address = address;
this.condition = condition;
this.toString = function() {
var t = Global().printer.theme;
return t.flow('while') + ' (' + this.condition + ');' + (__debug ? t.comment(' // 0x' + this.address.toString(16)) : '');
};
this.print = function() {
_print_block_data(this);
var offset = Global().evars.honor.offsets ? Extra.align_address(this.address) : '';
Global().context.printLine(Global().context.identfy(offset.length, Global().printer.theme.integers(offset)) + this.toString(), this.address);
};
}
};
+89
View File
@@ -0,0 +1,89 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import rzpipe from '../rzpipe.js';
import Utils from './utils.js';
var _compare = function(a, b) {
if (a.eq(b.location)) {
return 0;
} else if (a.lt(b.location)) {
return 1;
}
return -1;
};
var _str_compare_location = function(a, b) {
return a.location.lt(b.location) ? -1 : (a.location.eq(b.location) ? 0 : 1);
};
var _str_compare_size = function(a, b) {
return a.value < b.value ? -1 : (a.value == b.value ? 0 : 1);
};
var _sanitize = function(x) {
return x.paddr || x.vaddr || x.offset;
};
var _flag_filter = function(x) {
var ch = x.charAt(0);
if ((ch >= 'a'.charAt(0) && ch <= 'z'.charAt(0)) || (ch >= 'A'.charAt(0) && ch <= 'Z'.charAt(0)) || (ch >= '0'.charAt(0) && ch <= '9'.charAt(0))) {
return x;
}
switch (ch) {
case '\\'.charAt(0):
case ':'.charAt(0):
case '.'.charAt(0):
case '_'.charAt(0):
return x;
}
return '_';
};
/*
* Expects the Csj json as input.
*/
export default function(Csj, sort_by_size) {
this.data = Csj.filter(_sanitize).map(function(x) {
return {
location: Global().evars.honor.paddr ? x.paddr : x.vaddr || x.offset,
value: atob(x.string || x.name).replace(/\\\\/g, '\\')
};
}).sort(sort_by_size ? _str_compare_size : _str_compare_location);
this.search = function(address) {
if (address) {
if (!Global().evars.extra.slow) {
var x = rzpipe.string('Cs.q @ 0x' + address.toString(16));
if (x) {
x = x.substr(1);
return x.substr(0, x.length - 1);
}
}
var r = Utils.search(address, this.data, _compare);
return r ? r.value : null;
}
return null;
};
this.search_by_flag = function(flag) {
if (flag && flag.startsWith('str.')) {
if (!Global().evars.extra.slow) {
var address = rzpipe.string('s @ ' + flag);
var x = rzpipe.string('Cs.q @ ' + address.toString(16));
if (x) {
x = x.substr(1);
return x.substr(0, x.length - 1);
}
}
for (var i = 0; i < this.data.length; i++) {
var elem = 'str.' + this.data[i].value.split('').map(_flag_filter).join('').trim();
elem = elem.replace(/\\[abnrtv]/g, '_').replace(/\\/g, '_');
elem = elem.replace(/^str._+/, 'str.');
elem = elem.replace(/_+$/, '');
if (elem == flag) {
return this.data[i].value;
}
}
}
return null;
};
}
+61
View File
@@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import rzpipe from '../rzpipe.js';
import Utils from './utils.js';
import Long from '../long.js';
var _compare = function(a, b) {
if (a.eq(b.location)) {
return 0;
} else if (a.lt(b.location)) {
return 1;
}
return -1;
};
var _virtual_compare = function(a, b) {
return a.vaddr.lt(b.vaddr) ? -1 : (a.vaddr.eq(b.vaddr) ? 0 : 1);
};
var _physical_compare = function(a, b) {
return a.paddr.lt(b.paddr) ? -1 : (a.paddr.eq(b.paddr) ? 0 : 1);
};
var _sanitize = function(x) {
return x.paddr || x.vaddr;
};
/*
* Expects the isj json as input.
*/
export default function(isj) {
this.data = isj.filter(_sanitize).sort(Global().evars.honor.paddr ? _physical_compare : _virtual_compare).map(function(x) {
return {
location: Global().evars.honor.paddr ? x.paddr : x.vaddr,
value: (x.demname && x.demname.length > 0) ? x.demname : x.name,
};
});
this.search = function(address) {
const evars = Global().evars;
if (!address) {
return null;
} else if (!Long.isLong(address)) {
address = Long.from(address, true);
}
if (!evars.extra.slow) {
var def = {
symbols: {}
};
var x = rzpipe.json('is.j @ 0x' + address.toString(16), def);
if (x.length != 1) {
return null;
}
x = x[0];
var loc = (evars.honor.paddr ? x.paddr : x.vaddr) || Long.MAX_U64_VALUE;
return address.eq(loc) && !Long.MAX_U64_VALUE.eq(loc) ? ((x.demname && x.demname.length > 0) ? x.demname : x.name) : null;
}
var r = Utils.search(address, this.data, _compare);
return r ? r.value : null;
};
}
+35
View File
@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
var _default_cmp = function(a, b) {
return a - b;
};
export default {
indexOf: function(value, array, compare) {
if (!compare) {
compare = _default_cmp;
}
var min = 0;
var max = array.length - 1;
var index;
while (min <= max) {
index = (min + max) >> 1;
var cmp = compare(value, array[index]);
if (cmp === 0) {
return index;
} else {
if (cmp < 0) {
min = index + 1;
} else {
max = index - 1;
}
}
}
return -1;
},
search: function(value, array, compare) {
var pos = this.indexOf(value, array, compare);
return pos >= 0 ? array[pos] : null;
}
};
+184
View File
@@ -0,0 +1,184 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-FileCopyrightText: 2018-2019 elicn
// SPDX-License-Identifier: BSD-3-Clause
import Extra from './extra.js';
import Objects from './objects.js';
import Long from '../long.js';
var _internal_label_cnt = 0;
var _internal_variable_cnt = 0;
// ---------- inner functions ----------
var parenthesize = function(s) {
return ['(', s, ')'].join('');
};
var autoParen = function(s) {
return (s.indexOf(' ') > (-1) ? parenthesize(s) : s);
};
// ---------- inner objects ----------
var _label = function(name, address) {
this.name = name;
this.address = address;
this.toString = function() {
return Global().printer.theme.labels(this.name);
};
};
var _func_ptr = function(name, type, args) {
this.name = name;
this.type = type;
this.args = args.map(function(x) {
return x.toType ? x.toType() : ('uint' + Global().evars.archbits + '_t');
});
this.toType = function() {
return Global().printer.theme.types(this.type) + ' (*)(' + this.args.join(', ') + ')';
};
this.toString = function() {
return Global().printer.theme.types(this.type) + ' (*' + Global().printer.auto(this.name) + ')(' + this.args.join(', ') + ')';
};
};
var _ptr = function(name, type, pointer) {
this.name = name;
this.type = type;
this.pointer = pointer;
this.toType = function() {
return Global().printer.theme.types(this.type) + '*';
};
this.toString = function(define) {
if (define) {
var suffix = '';
if (this.pointer) {
suffix = ' = ' + Global().printer.auto(this.pointer);
}
return Global().printer.theme.types(this.type) + '* ' + this.name + suffix;
}
var c = '*(';
if (Global().evars.honor.casts) {
c += '(' + Global().printer.theme.types(this.type) + '*) ';
}
return c + Global().printer.auto(autoParen(this.name)) + ')';
};
};
var _local = function(name, type) {
this.name = name;
this.type = type;
this.toType = function() {
return Global().printer.theme.types(this.type);
};
this.toString = function(define) {
if (define) {
return Global().printer.theme.types(this.type) + ' ' + Global().printer.auto(this.name);
}
return Global().printer.auto(this.name);
};
};
var _string = function(content) {
this.content = content;
if (!this.content.startsWith('"') && !this.content.startsWith("'")) {
this.content = '"' + this.content;
}
if (!this.content.endsWith('"') && !this.content.endsWith("'")) {
this.content += '"';
}
this.content = this.content.replace(/\n/g, '\\n').replace(/\r/g, '\\r');
this.toType = function() {
return Global().printer.theme.types('char') + '*';
};
this.toString = function(define) {
return define ? null : Global().printer.theme.text(this.content);
};
};
var _number = function(content) {
this.content = Long.isLong(content) ? ('0x' + content.toString(16)) : content;
this.toType = function() {
return '';
};
this.toString = function(define) {
return define ? null : Global().printer.theme.integers(this.content);
};
};
var _macro = function(content) {
this.content = content;
this.toType = function() {
return '';
};
this.toString = function(define) {
return define ? null : Global().printer.theme.macro(this.content);
};
};
// ------------------------------
export default {
uniqueName: function(variable_name) {
var n = _internal_variable_cnt++;
return [variable_name ? variable_name : "value", n].join('_');
},
newLabel: function(address) {
var n = _internal_label_cnt++;
return new _label(['label', n].join('_'), address);
},
functionPointer: function(variable_name, bits, arguments_type) {
return new _func_ptr(variable_name, Extra.to.type(bits || 0), arguments_type || []);
},
globalPointer: function(variable_name, ctype_or_bits, is_signed, pointer) {
var ctype = Extra.is.number(ctype_or_bits) ? Extra.to.type(ctype_or_bits, is_signed) : ctype_or_bits;
return new _ptr(variable_name, ctype, pointer);
},
pointer: function(variable_name, ctype_or_bits, is_signed) {
var ctype = Extra.is.number(ctype_or_bits) ? Extra.to.type(ctype_or_bits, is_signed) : ctype_or_bits;
return new _ptr(variable_name, ctype);
},
local: function(variable_name, ctype_or_bits, is_signed) {
var ctype = Extra.is.number(ctype_or_bits) ? Extra.to.type(ctype_or_bits, is_signed) : ctype_or_bits;
return new _local(variable_name, ctype);
},
string: function(string_content) {
return new _string(string_content);
},
number: function(number) {
return new _number(number);
},
macro: function(string_content) {
return new _macro(string_content);
},
object: function(type, args) {
return Objects.object(type, args, false);
},
newobject: function(type, args) {
return Objects.object(type, args, true);
},
newarray: function(type, size, init) {
return Objects.array(type, size, true, null, init);
},
};
+20
View File
@@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: 2019-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
export default function(strings, symbols, classes) {
this.db_strings = strings;
this.db_symbols = symbols;
this.db_classes = classes;
this.find_symbol = function(address) {
return this.db_symbols.search(address);
};
this.find_string = function(value) {
if (typeof value == 'string') {
return this.db_strings.search_by_flag(value);
}
return this.db_strings.search(value);
};
this.find_class = function(address) {
return this.db_classes.search(address);
};
}
+135
View File
@@ -0,0 +1,135 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
var mident = ' ';
var _unique_print = {
rotate_left: [],
rotate_right: [],
bit_mask: false,
swap_endian: [],
};
export default {
rotate_left: {
macros: ['#include <stdint.h>', '#include <limits.h>'],
fcn: function(bits) {
this.bits = '' + bits;
this.name = 'rotate_left###';
this.returns = 'uint###_t';
this.args = ['uint###_t', 'value', 'uint32_t', 'count'];
this.data = [
mident + 'const uint###_t mask = (CHAR_BIT * sizeof (value)) - 1;',
mident + 'count &= mask;',
mident + 'return (value << count) | (value >> (-count & mask));'
];
this.print = function(offset) {
if (_unique_print.rotate_left.indexOf(this.bits) >= 0) {
return;
}
_unique_print.rotate_left.push(this.bits);
var i;
var bits = this.bits;
var call = this.name.replace(/###/g, bits);
var type = this.returns.replace(/###/g, bits);
var args = this.args.map(function(x) {
return x.replace(/###/g, bits);
});
args = args[0] + ' ' + args[1] + ', ' + args[2] + ' ' + args[3];
var a = Global().printer.auto;
var t = Global().printer.theme;
Global().context.printLine(Global().context.identfy() + t.types(type) + ' ' + t.callname(call) + ' (' + args + ') {', offset);
for (i = 0; i < this.data.length; i++) {
Global().context.printLine(Global().context.identfy() + a(this.data[i].replace(/###/g, this.bits)), offset);
}
Global().context.printLine(Global().context.identfy() + '}', offset);
};
}
},
rotate_right: {
macros: ['#include <stdint.h>', '#include <limits.h>'],
fcn: function(bits) {
this.bits = '' + bits;
this.name = 'rotate_right###';
this.returns = 'uint###_t';
this.args = ['uint###_t', 'value', 'uint32_t', 'count'];
this.data = [
mident + 'const uint###_t mask = (CHAR_BIT * sizeof (value)) - 1;',
mident + 'count &= mask;',
mident + 'return (value >> count) | (value << (-count & mask));'
];
this.print = function(offset) {
if (_unique_print.rotate_right.indexOf(this.bits) >= 0) {
return;
}
_unique_print.rotate_right.push(this.bits);
var i;
var bits = this.bits;
var call = this.name.replace(/###/g, bits);
var type = this.returns.replace(/###/g, bits);
var args = this.args.map(function(x) {
return x.replace(/###/g, bits);
});
var a = Global().printer.auto;
var t = Global().printer.theme;
args = args[0] + ' ' + args[1] + ', ' + args[2] + ' ' + args[3];
Global().context.printLine(Global().context.identfy() + t.types(type) + ' ' + t.callname(call) + ' (' + args + ') {', offset);
for (i = 0; i < this.data.length; i++) {
Global().context.printLine(Global().context.identfy() + a(this.data[i].replace(/###/g, this.bits)), offset);
}
Global().context.printLine(Global().context.identfy() + '}', offset);
};
}
},
bit_mask: {
macros: [
'#include <limits.h>',
],
fcn: function() {
this.mask = '#define BIT_MASK(t,v) ((t)(-((v)!= 0)))&(((t)-1)>>((sizeof(t)*CHAR_BIT)-(v)))';
this.print = function(offset) {
if (_unique_print.bit_mask) {
return;
}
_unique_print.bit_mask = true;
var t = Global().printer.theme;
Global().context.printLine(Global().context.identfy() + t.macro(this.mask), offset);
};
}
},
swap_endian: {
macros: [],
fcn: function(bits) {
this.bits = bits;
this.data = [];
if (bits == 16) {
this.data.push('#define SWAP16(n) ((uint16_t) (((n & 0x00ff) << 8) | \\');
this.data.push(' ((n & 0xff00) >> 8)))');
} else if (bits == 32) {
this.data.push('#define SWAP32(n) ((uint32_t) (((n & 0x000000ff) << 24) | \\');
this.data.push(' ((n & 0x0000ff00) << 8) | \\');
this.data.push(' ((n & 0x00ff0000) >> 8) | \\');
this.data.push(' ((n & 0xff000000) >> 24)))');
} else {
this.bits = 64;
this.data.push('#define SWAP64(val) ((uint64_t) (((val & 0x00000000000000ffull) << 56) | \\');
this.data.push(' ((val & 0x000000000000ff00ull) << 40) | \\');
this.data.push(' ((val & 0x0000000000ff0000ull) << 24) | \\');
this.data.push(' ((val & 0x00000000ff000000ull) << 8) | \\');
this.data.push(' ((val & 0x000000ff00000000ull) >> 8) | \\');
this.data.push(' ((val & 0x0000ff0000000000ull) >> 24) | \\');
this.data.push(' ((val & 0x00ff000000000000ull) >> 40) | \\');
this.data.push(' ((val & 0xff00000000000000ull) >> 56)))');
}
this.print = function(offset) {
if (_unique_print.swap_endian.indexOf(this.bits) >= 0) {
return;
}
_unique_print.swap_endian.push(this.bits);
var t = Global().printer.theme;
for (var i = 0; i < this.data.length; i++) {
Global().context.printLine(Global().context.identfy() + t.macro(this.data[i]), offset);
}
};
}
}
};
+52
View File
@@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
const _known_cpp_data = {
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>,std::allocator<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>': 'std::string',
'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::basic_stringstream': 'std::stringstream ',
'std::basic_istringstream<char,std::char_traits<char>,std::allocator<char>>::basic_istringstream': 'std::istringstream ',
'std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>::basic_ostringstream': 'std::ostringstream ',
'std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::~basic_stringstream': 'std::~stringstream ',
'std::basic_istringstream<char,std::char_traits<char>,std::allocator<char>>::~basic_istringstream': 'std::~istringstream ',
'std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>::~basic_ostringstream': 'std::~ostringstream ',
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string': 'std::string ',
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string': 'std::~string ',
'std::basic_string<char,std::char_traits<char>,std::allocator<char>>': 'std::string ',
'std::basic_ostream<char,std::char_traits<char>>': 'std::string ',
'std::basic_istream<char,std::char_traits<char>>': 'std::string ',
'operatordelete(void*)': 'delete',
'<char,std::char_traits<char>,std::allocator<char>>': ' ',
'<std::char_traits<char>>': 'std::string ',
'std::_Ios_Openmode': 'std::ios_base::openmode ',
'&std::operator>>': '& std::operator >> ',
'&std::operator<<': '& std::operator << ',
'&std::operator[]': '& std::operator [] ',
'&std::operator|': '& std::operator | ',
'&std::operator+': '& std::operator + ',
'&std::operator+=': '& std::operator += ',
'operator>>': 'operator >> ',
'operator<<': 'operator << ',
'operator[]': 'operator [] ',
'operator|': 'operator | ',
'std::stringconst': 'std::string const',
'unsignedlong': 'unsigned long',
'longlong': 'long long',
'charconst': 'char const',
};
export default function(str) {
str = str.replace(/::_cxx\d\d::/g, '::').replace(/\s+/g, '');
for (var key in _known_cpp_data) {
if (str.indexOf(key) >= 0) {
var find = new RegExp(key.replace(/([()[\]|\\*+])/g, '\\$1'), 'g');
str = str.replace(find, _known_cpp_data[key]);
}
}
return str;
}
+251
View File
@@ -0,0 +1,251 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
/**
* On rizin this can be done via afcfj <function name>
* [
* {
* "name": "localtime",
* "return": "struct tm *",
* "count": 1,
* "args": [
* {
* "name": "timer",
* "type": "const time_t *"
* }
* ]
* }
* ]
*/
export default {
'libc_start_main': {
macro: [],
required: 7
},
'exit': {
macro: ['#include <stdlib.h>'],
required: 1
},
'access': {
macro: ['#include <stdio.h>'],
required: 2
},
'fscanf': {
macro: ['#include <stdio.h>'],
required: 2,
varargs: true
},
'fgets': {
macro: ['#include <stdio.h>'],
required: 3
},
'fclose': {
macro: ['#include <stdio.h>'],
required: 1
},
'fopen': {
macro: ['#include <stdio.h>'],
required: 2
},
'fwrite': {
macro: ['#include <stdio.h>'],
required: 4
},
'fread': {
macro: ['#include <stdio.h>'],
required: 4
},
'textdomain': {
macro: ['#include <libintl.h>'],
required: 2
},
'bindtextdomain': {
macro: ['#include <libintl.h>'],
required: 2
},
'setlocale': {
macro: ['#include <locale.h>'],
required: 2
},
'wcscmp': {
macro: ['#include <wchar.h>'],
required: 2
},
'strcmp': {
macro: ['#include <string.h>'],
required: 2
},
'strncmp': {
macro: ['#include <string.h>'],
required: 3
},
'msvcrt_dll_memset': {
macro: ['#include <string.h>'],
required: 3
},
'xmalloc': {
macro: ['#include <stdlib.h>'],
required: 1
},
'memset': {
macro: ['#include <string.h>'],
required: 3
},
'memcpy': {
macro: ['#include <string.h>'],
required: 3
},
'strcpy': {
macro: ['#include <string.h>'],
required: 2
},
'puts': {
macro: ['#include <stdio.h>'],
required: 1
},
'fprintf': {
macro: ['#include <stdio.h>'],
required: 2,
varargs: true
},
'printf': {
macro: ['#include <stdio.h>'],
required: 1,
varargs: true
},
'scanf': {
macro: ['#include <stdio.h>'],
required: -1,
varargs: true
},
'getenv': {
macro: ['#include <stdlib.h>'],
required: 1
},
'time': {
macro: ['#include <time.h>'],
required: 1
},
'localtime': {
macro: ['#include <time.h>'],
required: 1
},
'dcgettext': {
macro: ['#include <libintl.h>'],
required: 2
},
'pthread_create': {
macro: ['#include <pthread.h>'],
required: 4,
},
'pthread_join': {
macro: ['#include <pthread.h>'],
required: 2,
},
'pthread_exit': {
macro: ['#include <pthread.h>'],
required: 1,
},
'pthread_cancel': {
macro: ['#include <pthread.h>'],
required: 1,
},
'pthread_attr_init': {
macro: ['#include <pthread.h>'],
required: 1,
},
'pthread_attr_destroy': {
macro: ['#include <pthread.h>'],
required: 1,
},
'socket': {
macro: ['#include <pthread.h>'],
required: 3,
},
'accept': {
macro: ['#include <sys/socket.h>'],
required: 3,
},
'bind': {
macro: ['#include <sys/socket.h>'],
required: 3,
},
'connect': {
macro: ['#include <sys/socket.h>'],
required: 3,
},
'getsockname': {
macro: ['#include <sys/socket.h>'],
required: 3,
},
'listen': {
macro: ['#include <sys/socket.h>'],
required: 2,
},
'recv': {
macro: ['#include <sys/socket.h>'],
required: 2,
},
'recvfrom': {
macro: ['#include <sys/socket.h>'],
required: 6,
},
'recvmsg': {
macro: ['#include <sys/socket.h>'],
required: 2,
},
'open': {
macro: ['#include <unistd.h>'],
required: 3,
},
'creat': {
macro: ['#include <unistd.h>'],
required: 2,
},
'close': {
macro: ['#include <unistd.h>'],
required: 1,
},
'read': {
macro: ['#include <unistd.h>'],
required: 3,
},
'write': {
macro: ['#include <unistd.h>'],
required: 3,
},
'daemon': {
macro: ['#include <unistd.h>'],
required: 2,
},
'perror': {
macro: ['#include <stdio.h>'],
required: 1,
},
'shmget': {
macro: ['#include <sys/shm.h>'],
required: 3,
},
'shmat': {
macro: ['#include <sys/shm.h>'],
required: 3,
},
'signal': {
macro: ['#include <signal.h>'],
required: 1,
},
/* iOS */
'UIApplicationMain': {
macro: [],
required: 4,
},
'NSStringFromClass': {
macro: [],
required: 1,
},
'NSLog': {
macro: [],
required: 1,
varargs: true
}
};
File diff suppressed because it is too large. Load diff
+15
View File
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2017-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import core from './core.js';
import archs from './archs.js';
import context from './context.js';
export default {
core: core,
archs: archs,
context: context,
supported: function() {
return 'Supported architectures:\n ' + Object.keys(this.archs).join(', ');
}
};
+95
View File
@@ -0,0 +1,95 @@
// SPDX-FileCopyrightText: 2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
function to64(n, unsigned) {
if (unsigned) {
return BigInt.asUintN(64, n);
}
return BigInt.asIntN(64, n);
}
function toNum(num, unsigned) {
const itype = typeof num;
if (itype === 'bigint') {
return num;
} else if (itype === 'number') {
const isNeg = num < 0;
if (isNeg) {
num = -num;
}
num = BigInt(num);
if (isNeg) {
num = 0n - num;
}
return BigInt.asIntN(64, num);
} else if (Long.isLong(num)) {
return num.value;
}
throw new Error("Unexpected type: " + (typeof num));
}
function Long(value, isUnsigned) {
this.unsigned = isUnsigned;
this.value = to64(value, isUnsigned);
this.isLong = true;
this.toString = function(x) { return this.value.toString(x); };
this.add = function(x) { return new Long(this.value + toNum(x, this.unsigned), this.unsigned); };
this.sub = function(x) { return new Long(this.value - toNum(x, this.unsigned), this.unsigned); };
this.shl = function(x) { return new Long(this.value << toNum(x, this.unsigned), this.unsigned); };
this.shru = function(x) { return new Long(this.value >> toNum(x, this.unsigned), this.unsigned); };
this.and = function(x) { return new Long(this.value & toNum(x, this.unsigned), this.unsigned); };
this.or = function(x) { return new Long(this.value | toNum(x, this.unsigned), this.unsigned); };
this.xor = function(x) { return new Long(this.value ^ toNum(x, this.unsigned), this.unsigned); };
this.not = function() { return new Long(!this.value, this.unsigned); };
this.eq = function(x) { return this.value == toNum(x, this.unsigned); };
this.ne = function(x) { return this.value != toNum(x, this.unsigned); };
this.lt = function(x) { return this.value < toNum(x, this.unsigned); };
this.gt = function(x) { return this.value > toNum(x, this.unsigned); };
this.lte = function(x) { return this.value <= toNum(x, this.unsigned); };
this.gte = function(x) { return this.value >= toNum(x, this.unsigned); };
}
Long.isLong = function(value) {
return value && typeof value == "object" && value.isLong;
};
Long.from = function(input, isUnsigned, base) {
const itype = typeof input;
if (itype === 'bigint') {
return new Long(input, isUnsigned);
} else if (itype === 'number') {
let value = BigInt(input);
return new Long(value, isUnsigned);
} else if (itype === 'string') {
if (input.length < 1) {
return isUnsigned ? Long.UZERO : Long.ZERO;
}
const isNeg = input.startsWith("-");
if (isNeg) {
input = input.substr(1);
}
if (base == 16 && !input.startsWith('0x')) {
input = "0x" + input;
}
let value = BigInt(input);
if (isNeg) {
value = 0n - value;
}
return new Long(value, isUnsigned);
} else if (Long.isLong(input)) {
return input;
}
throw new Error("Invalid type for Long (" + itype + ') with args ' + [...arguments].join(', '));
};
Long.ZERO = Long.from(0, false);
Long.UZERO = Long.from(0, true);
Long.MAX_U64_VALUE = new Long(Limits.UT64_MAX, true);
Long.MAX_U32_VALUE = new Long(Limits.UT32_MAX, true);
Long.MAX_U16_VALUE = new Long(Limits.UT16_MAX, true);
Long.MAX_S64_VALUE = new Long(Limits.ST64_MAX, false);
Long.MAX_S32_VALUE = new Long(Limits.ST32_MAX, false);
Long.MAX_S16_VALUE = new Long(Limits.ST16_MAX, false);
export default Long;
+183
View File
@@ -0,0 +1,183 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import JSONex from './JSONex.js';
import Long from './long.js';
import Anno from './annotation.js';
import ColorsAnsi from './colors/ansi.js';
import ColorsInvalid from './colors/invalid.js';
function initializeColors() {
const config = {};
const colors = rizin ? rizin.command("ec*") : '';
colors.split('\n').forEach(function(line) {
const tok = line.split(' ');
config[tok[1]] = tok[2];
});
return {
"callname": config['call'] || 'gray',
"integers": config['num'] || 'cyan',
"comment": config['comment'] || 'red',
"labels": config['flag'] || 'green',
"types": config['func_var_type'] || 'green',
"macro": config['cjmp'] || 'yellow',
"flow": config['flow'] || 'magenta',
"text": config['usrcmt'] || 'yellow',
};
}
//const _autoregex = /(\bif\b|\belse\b|\bwhile\b|\bfor\b|\bdo\b|\breturn\b|[ui]+nt[123468]+\_t|\bvoid\b|\bconst\b|\bsizeof\b|\bfloat\b|\bdouble\b|0x[0-9A-Fa-f]+|\b\d+\b)/g
/**
* Contains the regex used to colorize a given string.
* @type {Object}
*/
const _autotheme = {
controlflow: /\bif\b|\belse\b|\bwhile\b|\bfor\b|\bdo\b|\breturn\b|\bthrow\b/g,
definebits: /[ui]+nt[123468]+_t|\bvoid\b|\bconst\b|\bsizeof\b|\bfloat\b|\bdouble\b|\bchar\b|\bwchar_t\b|\bextern\b|\bstruct\b|\bsize_t\b|\btime_t\b|\bboolean\b/g,
numbers: /0x[0-9a-fA-F]+|\b(?![;[])\d+(?![;m])\b/g,
string: /("[^"]+")/,
};
const defaulttheme = initializeColors();
/**
* Color types (ansi, nocolor)
* @type {Object}
*/
const Colors = {
ansi: ColorsAnsi,
text: ColorsInvalid,
};
var _theme_colors = Colors.text.make(defaulttheme);
/**
* Applies colors to the string given a certain regex
* @param {String} input - Input string
* @param {String} type - Color name (ansi, text)
* @param {String} regex - Regex to apply
* @return {String} - Result string
*/
var _apply_regex = function(input, type, regex) {
var x = input.split(regex);
var p = input.match(regex);
var s = '';
if (!p) {
return s;
}
var i = 0;
for (i = 0; i < p.length; i++) {
if (p[i].length > 0) {
s += x[i] + _theme_colors[type](p[i]);
} else {
s += x[i] + p[i];
}
}
for (; i < x.length; i++) {
s += x[i];
}
return s;
};
/**
* Colorize the input string via ansi converters
* @param {String} input - Input string
* @return {String} - Result string
*/
var _colorize_text = function(input) {
if (!input || input.length < 1) {
return '';
}
if (!Global().evars.honor.color) {
return input;
}
/* control flow (if, else, while, do, etc..) */
var x = input.split(_autotheme.controlflow);
if (x.length > 1) {
input = _apply_regex(input, 'flow', _autotheme.controlflow);
}
/* numbers */
x = input.split(_autotheme.numbers);
if (x.length == 1 && x == '') {
input = this.theme.integers(input);
} else if (x.length > 1) {
input = _apply_regex(input, 'integers', _autotheme.numbers);
}
/* uint32_t, etc.. */
x = input.split(_autotheme.definebits);
if (x.length == 1 && x == '') {
input = this.theme.types(input);
} else if (input.split(_autotheme.definebits).length > 1) {
input = _apply_regex(input, 'types', _autotheme.definebits);
}
return input;
};
/**
* Applies all the colors options (theme/colors).
*/
var _get_theme = function(evars) {
if (evars.honor && evars.honor.color) {
return Colors.ansi.make(defaulttheme);
}
return Colors.text.make(defaulttheme);
};
/**
* Prints the final jsdec output
* @param useJSON - boolean whether to print as json
*/
var _flush_output = function(lines, errors, log) {
if (Global().evars.extra.annotation && lines) {
var actx = Anno.context();
var res = {
code: "",
annotations: []
};
lines.forEach(function(x) {
var parsed = Anno.parse(res.code.length, x, actx);
res.annotations = res.annotations.concat(parsed);
res.code += x.str + '\n';
});
console.log(JSONex.stringify(res));
} else if (Global().evars.extra.json) {
var jdata = {};
if (lines && lines.length > 0) {
jdata.lines = lines;
}
if (errors && errors.length > 0) {
jdata.errors = errors;
}
if (log && log.length > 0) {
jdata.log = log;
}
console.log(JSONex.stringify(jdata));
} else {
var prefix = Global().evars.extra.allfunctions ? "// " : "";
if (lines && lines.length > 0) {
for (var i = 0; i < lines.length; i++) {
if (Global().evars.extra.highlights && Global().evars.extra.offset.eq(lines[i].offset || Long.ZERO)) {
console.log('\u001b[7m' + lines[i].str + '\u001b[49m\u001b[0m');
} else {
console.log(lines[i].str);
}
}
}
if (errors && errors.length > 0) {
console.log(prefix + errors.join("\n").replace(/\n/g, '\n' + prefix));
}
if (log && log.length > 0) {
console.log(prefix + log.join("\n").replace(/\n/g, '\n' + prefix));
}
}
};
/**
* Printer Object
* @return {Function} - Printer object (to be called via `new Printer()`)
*/
export default function() {
this.theme = _get_theme(Global().evars);
this.auto = _colorize_text;
this.flushOutput = _flush_output;
}
+63
View File
@@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: 2019-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import JSONex from './JSONex.js';
import Long from './long.js';
function rzcustom(value, regex, function_fix) {
var x = rizin.command(value) || "";
if (regex) {
x = x.replace(regex, '');
}
return function_fix ? function_fix(x.trim()) : x.trim();
}
function rzstr(value, multiline) {
var x = rizin.command(value) || "";
if (multiline) {
x = x.replace(/\n/g, '');
}
return x.trim();
}
function rzjson(m, def) {
var x = rzstr(m, true);
try {
return x.length > 0 ? JSONex.parse(x) : def;
} catch(e){}
return def;
}
function rzint(value, def) {
var x = rzstr(value);
if (x != '') {
try {
return parseInt(x);
} catch (e) {}
}
return def || 0;
}
function rzlong(value, def) {
var x = rzstr(value);
if (x != '') {
try {
return Long.from(x, true);
} catch (e) {}
}
return def || Long.UZERO;
}
function rzbool(value) {
var x = rzstr(value);
return x == 'true' || x == '1';
}
export default {
custom: rzcustom,
string: rzstr,
json: rzjson,
int: rzint,
long: rzlong,
bool: rzbool,
};
+256
View File
@@ -0,0 +1,256 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import rzpipe from './rzpipe.js';
import JSONex from './JSONex.js';
import libdec from './libdec.js';
export default (function() {
var __line_cnt = 0;
function rz_sanitize(value, expected) {
return value.length == 0 ? expected : value;
}
function jsdec_sanitize(enable, evar, oldstatus, newstatus) {
if (enable) {
rizin.command('e ' + evar + '=' + newstatus);
} else {
rizin.command('e ' + evar + '=' + oldstatus);
}
}
function merge_arrays(input) {
input = input.replace(/\n/g, ',');
var array = '[' + input + ']';
return array;
}
function merge_arrays_json(input) {
return JSONex.parse(merge_arrays(input));
}
var padding = ' ';
var usages = {
"--help": "this help message",
"--architectures": "lists the supported architectures",
"--all-functions": "decompile all functions",
"--assembly": "shows pseudo next to the assembly",
"--blocks": "shows only scopes blocks",
"--casts": "shows all casts in the pseudo code",
"--colors": "enables syntax colors",
"--debug": "do not catch exceptions",
"--issue": "generates the json used for the test suite",
"--offsets": "shows pseudo next to the assembly offset",
"--paddr": "all xrefs uses physical addresses instead of virtual addresses",
"--xrefs": "shows also instruction xrefs in the pseudo code",
"--highlight-current": "highlights the current address.",
"--as-comment": "the decompiled code is returned to r2 as comment (via CCu)",
"--as-code-line": "the decompiled code is returned to r2 as 'file:line code' (via CL)",
"--as-json": "the decompiled code lines are returned as JSON",
"--annotation": "the decompiled code lines are returned with the annotation format"
};
function has_option(args, name) {
return (args.indexOf(name) >= 0);
}
function has_invalid_args(args) {
for (var i = 0; i < args.length; i++) {
if (args[i] != '' && !usages[args[i]]) {
console.log('Invalid argument \'' + args[i] + '\'\n');
return true;
}
}
return false;
}
function usage() {
console.log("jsdec [options]");
for (var key in usages) {
var cmd = key + padding.substr(key.length, padding.length);
console.log(" " + cmd + " | " + usages[key]);
}
}
function print_issue() {
var xrefs = rz_sanitize(rzpipe.string('isj'), '[]');
var strings = rz_sanitize(rzpipe.string('Cslj'), '[]');
var functions = rz_sanitize(rzpipe.string('aflj'), '[]');
var classes = rz_sanitize(rzpipe.string('icj'), '[]');
var data = JSONex.stringify(rizin.graph());
var farguments = rz_sanitize(rzpipe.string('afvlj', true), '{"stack":[],"reg":[]}');
var arch = rz_sanitize(rzpipe.string('e asm.arch'), '');
var archbits = rz_sanitize(rzpipe.string('e asm.bits'), '32');
var database = rz_sanitize(rzpipe.custom('afsj @@i', null, merge_arrays), '[]');
console.log('{"name":"issue_' + (new Date()).getTime() +
'","arch":"' + arch +
'","archbits":' + archbits +
',"graph":' + data +
',"isj":' + xrefs +
',"Csj":' + strings +
',"icj":' + classes +
',"afvj":' + farguments +
',"afcfj":' + database +
',"aflj":' + functions + '}');
}
function print_archs() {
var archs = Object.keys(libdec.archs);
archs.sort();
console.log('Supported architectures: ' + archs.join(', '));
}
var rzutil = {
check_args: function(args) {
if (has_invalid_args(args)) {
args.push('--help');
}
if (has_option(args, '--help')) {
usage();
return true;
}
if (has_option(args, '--issue')) {
print_issue();
return true;
}
if (has_option(args, '--architectures')) {
print_archs();
return true;
}
return false;
},
evars: function(args) {
let o = {};
o.arch = rzpipe.string('e asm.arch');
o.archbits = rzpipe.int('e asm.bits', 32);
o.honor = {
casts: rzpipe.bool('e jsdec.casts') || has_option(args, '--casts'),
assembly: rzpipe.bool('e jsdec.asm') || has_option(args, '--assembly'),
blocks: rzpipe.bool('e jsdec.blocks') || has_option(args, '--blocks'),
xrefs: rzpipe.bool('e jsdec.xrefs') || has_option(args, '--xrefs'),
paddr: rzpipe.bool('e jsdec.paddr') || has_option(args, '--paddr'),
offsets: has_option(args, '--offsets'),
color: rzpipe.int('e scr.color', 0) > 0 || has_option(args, '--colors')
};
o.sanitize = {
ucase: rzpipe.bool('e asm.ucase'),
pseudo: rzpipe.bool('e asm.pseudo'),
capitalize: rzpipe.bool('e asm.capitalize'),
html: rzpipe.bool('e scr.html'),
syntax: rzpipe.string('e asm.syntax'),
};
o.extra = {
allfunctions: has_option(args, '--all-functions'),
ascodeline: has_option(args, '--as-code-line'),
ascomment: has_option(args, '--as-comment'),
debug: rzpipe.bool('e jsdec.debug') || has_option(args, '--debug'),
file: rzpipe.string('i~^file[1:0]'),
highlights: rzpipe.bool('e jsdec.highlight') || has_option(args, '--highlight-current'),
json: has_option(args, '--as-json'),
offset: rzpipe.long('s'),
slow: rzpipe.bool('e jsdec.slow'),
annotation: has_option(args, '--annotation'),
};
o.add_comment = function(comment, offset) {
if (!comment || comment.length < 1) {
return;
}
rizin.command('CC- @ 0x' + offset.toString(16));
rizin.command('CCu base64:' + btoa(comment) + ' @ 0x' + offset.toString(16));
};
o.add_code_line = function(comment, offset) {
if (comment.trim().length < 1) {
return;
}
var line = __line_cnt++;
rizin.command('"CL 0x' + offset.toString(16) + ' jsdec.c:' + line + ' ' + comment.replace(/\n/g, '; ').replace(/\\/g, '\\\\').replace(/"/g, '\\"') + ';"');
};
if (o.extra.ascomment || o.extra.ascodeline) {
o.honor.assembly = false;
o.honor.blocks = false;
o.honor.offsets = false;
o.extra.json = false;
o.honor.color = false;
o.extra.highlights = false;
o.extra.annotation = false;
}
if (o.extra.allfunctions) {
o.extra.ascomment = false;
o.extra.ascodeline = false;
o.honor.assembly = false;
o.honor.blocks = false;
o.honor.offsets = false;
o.extra.json = false;
o.extra.highlights = false;
o.extra.annotation = false;
}
if (o.extra.annotation) {
o.extra.ascodeline = false;
o.extra.ascomment = false;
o.extra.highlights = false;
o.extra.html = false;
o.extra.json = false;
o.honor.assembly = false;
o.honor.blocks = false;
o.honor.color = false;
o.honor.offsets = false;
}
if (o.sanitize.html || !o.honor.color) {
o.extra.highlights = false;
}
return o;
},
data: function(isfast) {
if (isfast === undefined) {
isfast = !rzpipe.bool('e jsdec.slow');
}
this.arch = rzpipe.string('e asm.arch');
this.bits = rzpipe.int('e asm.bits', 32);
this.xrefs = {
symbols: (isfast ? [] : rzpipe.json('isj', [])),
strings: (isfast ? [] : rzpipe.json('Cslj', [])),
functions: (isfast ? [] : rzpipe.json('aflj', [])),
classes: rzpipe.json('icj', []),
arguments: rzpipe.json('afvlj', {
"stack": [],
"reg": []
})
};
this.xrefs.arguments.stack = this.xrefs.arguments.stack || [];
this.xrefs.arguments.reg = this.xrefs.arguments.reg || [];
this.graph = rizin.graph();
this.argdb = rzpipe.custom('afsj @@i', null, merge_arrays_json);
},
sanitize: function(enable, evars) {
if (!evars) {
return;
}
var s = evars.sanitize;
jsdec_sanitize(enable, 'asm.ucase', s.ucase, 'false');
jsdec_sanitize(enable, 'asm.pseudo', s.pseudo, 'false');
jsdec_sanitize(enable, 'asm.capitalize', s.capitalize, 'false');
jsdec_sanitize(enable, 'scr.html', s.html, 'false');
if (evars.arch == 'x86') {
jsdec_sanitize(enable, 'asm.syntax', s.syntax, 'intel');
}
},
debug: function(evars, exception) {
rzutil.sanitize(false, evars);
if (!evars || evars.extra.debug) {
var msg = exception.message + ' (' + exception.name + ')';
return 'Exception: ' + msg + '\n' + exception.stack;
} else {
return '\n\njsdec has crashed (info: ' + rzpipe.string('i~^file[1:0]') + ' @ ' + rzpipe.string('s') + ').\n' +
'Please report the bug at https://github.com/rizinorg/jsdec/issues\n' +
'Use the option \'--issue\' or the command \'pddi\' to generate \n' +
'the needed data for the issue.';
}
}
};
return rzutil;
})();
+80
View File
@@ -0,0 +1,80 @@
// SPDX-FileCopyrightText: 2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
import Long from './long.js';
import JSONex from './JSONex.js';
function _new_evars(issue) {
let evars = {};
evars.arch = issue.arch;
evars.archbits = issue.bits;
evars.honor = {
assembly: true,
blocks: false,
casts: true,
offsets: false,
paddr: false,
pseudo: false,
xrefs: false,
};
evars.extra = {
allfuncs: false,
ascodeline: false,
ascomment: false,
debug: true,
file: 'testsuite',
highlights: false,
offset: Long.UZERO,
slow: true,
theme: 'default',
annotation: false,
};
return evars;
}
// old graph has base64 encoded comments.
function _fixup_old_graph(graph) {
graph[0].blocks.forEach((block) => {
block.ops.forEach((instr) => {
instr.comment = instr.comment ? atob(instr.comment) : undefined;
});
});
return graph;
}
function _new_data(issue) {
if (!issue.arch) {
throw new Error('missing architecture in JSON.');
}
let bits = issue.archbits || issue.bits || 32;
if (bits) {
// if bits is in the issue then it has been decoded as a Long object.
// to override this is required to be converted to just an integer.
bits = parseInt(bits.toString());
}
var testdata = {
arch: issue.arch,
bits: bits,
graph: issue.agj ? _fixup_old_graph(issue.agj) : (issue.graph || []),
xrefs: {
symbols: issue.isj || [],
strings: issue.Csj || issue.izj || [],
functions: issue.aflj || [],
classes: issue.icj || [],
arguments: issue.afvj || {
"stack": [],
"reg": []
}
},
argdb: issue.afcfj
};
testdata.xrefs.arguments.stack = testdata.xrefs.arguments.stack || [];
testdata.xrefs.arguments.reg = testdata.xrefs.arguments.reg || [];
return testdata;
}
export default function(filename) {
const issue = JSONex.parse(unit.raw);
this.data = _new_data(issue);
this.evars = _new_evars(this.data);
}
+12
View File
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2018-2023 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
export default function(message) {
if (typeof message == 'string') {
message = "[!] " + message;
if (this.printer.theme.comment) {
message = this.printer.theme.comment(message);
}
this.context.printLog(message);
}
}
+31
View File
@@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: 2023 Giovanni Dante Grazioli <[email protected]>
# SPDX-License-Identifier: BSD-3-Clause
jsdec_plugin = 'jsdec-plugin.js'
jsdec_testsuite = 'jsdec-testsuite.js'
if get_option('build_type') == 'standalone'
bytecode_h = custom_target(
'bytecode.h',
build_always_stale: true,
output : 'bytecode.h',
input : jsdec_testsuite,
command : [qjsc, '-m', '-N', 'main_bytecode', '-o', '@OUTPUT@', '@INPUT@'],
)
else
bytecode_h = custom_target(
'bytecode.h',
build_always_stale: true,
output : 'bytecode.h',
input : jsdec_plugin,
command : [qjsc, '-m', '-N', 'main_bytecode', '-o', '@OUTPUT@', '@INPUT@'],
)
endif
bytecode_mod_h = custom_target(
'bytecode_mod.h',
build_always_stale: true,
output : 'bytecode_mod.h',
input : bytecode_h,
command : [modjs_gen, '@INPUT@', '@OUTPUT@'],
)
-113
View File
@@ -1,113 +0,0 @@
// SPDX-FileCopyrightText: 2017-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-FileCopyrightText: 2017-2018 pancake <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
/**
* Global data accessible from everywhere.
* @type {Object}
*/
var Global = {
context: null,
evars: null,
printer: null,
argdb: null,
warning: require('libdec/warning')
};
/**
* Imports.
*/
var libdec = require('libdec/libdec');
var rzutil = require('libdec/rzutil');
var rzpipe = require('libdec/rzpipe');
function decompile_offset(architecture, fcnname) {
var data = new rzutil.data();
Global.argdb = data.argdb;
// af seems to break renaming.
/* asm.pseudo breaks things.. */
if (data.graph && data.graph.length > 0) {
var p = new libdec.core.session(data, architecture);
var arch_context = architecture.context(data);
libdec.core.analysis.pre(p, architecture, arch_context);
libdec.core.decompile(p, architecture, arch_context);
libdec.core.analysis.post(p, architecture, arch_context);
libdec.core.print(p);
} else if (Global.evars.extra.allfunctions) {
Global.context.printLog('Error: Please analyze the ' + fcnname + ' first.', true);
} else {
Global.context.printLog('Error: no data available.\nPlease analyze the function/binary first.', true);
}
}
/**
* jsdec main function.
* @param {Array} args - jsdec arguments to be used to configure the output.
*/
function jsdec_main(args) { // lgtm [js/unused-local-variable]
var Printer = require('libdec/printer');
var lines = null;
var errors = [];
var log = [];
try {
Global.evars = new rzutil.evars(args);
rzutil.sanitize(true, Global.evars);
if (rzutil.check_args(args)) {
rzutil.sanitize(false, Global.evars);
return;
}
// theme (requires to be initialized after evars)
Global.printer = new Printer();
var architecture = libdec.archs[Global.evars.arch];
if (architecture) {
Global.context = new libdec.context();
var current = rzpipe.long('s');
if (Global.evars.extra.allfunctions) {
var functions = rzpipe.json64('aflj');
functions.forEach(function(x) {
if (x.name.startsWith('sym.imp.') || x.name.startsWith('loc.imp.')) {
return;
}
rzpipe.string('s 0x' + x.offset.toString(16));
Global.context.printLine("", x.offset);
Global.context.printLine(Global.printer.theme.comment('/* name: ' + x.name + ' @ 0x' + x.offset.toString(16) + ' */'), x.offset);
decompile_offset(architecture, x.name);
});
rzpipe.string('s 0x' + current.toString(16));
var o = Global.context;
Global.context = new libdec.context();
Global.context.macros = o.macros;
Global.context.dependencies = o.dependencies;
Global.context.printLine(Global.printer.theme.comment('/* jsdec pseudo code output */'), current);
Global.context.printLine(Global.printer.theme.comment('/* ' + Global.evars.extra.file + ' */'), current);
if (['java', 'dalvik'].indexOf(Global.evars.arch) < 0) {
Global.context.printMacros(true);
Global.context.printDependencies(true);
}
o.lines = Global.context.lines.concat(o.lines);
Global.context = o;
} else {
decompile_offset(architecture);
}
errors = errors.concat(Global.context.errors);
log = log.concat(Global.context.log);
lines = Global.context.lines;
} else {
errors.push(Global.evars.arch + ' is not currently supported.\n' +
'Please open an enhancement issue at https://github.com/rizinorg/jsdec/issues\n' +
libdec.supported());
}
rzutil.sanitize(false, Global.evars);
} catch (e) {
errors.push(rzutil.debug(Global.evars, e));
}
var printer = Global.printer;
if (!printer) {
printer = new Printer();
}
printer.flushOutput(lines, errors, log, Global.evars.extra);
}
-58
View File
@@ -1,58 +0,0 @@
// SPDX-FileCopyrightText: 2017-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
/**
* Global data accessible from everywhere.
* @type {Object}
*/
var Global = {
context: null,
evars: null,
printer: null
};
/**
* Imports.
*/
var libdec = require('libdec/libdec');
var rzutil = require('libdec/rzutil');
const rzcmd = null;
/**
* jsdec main function.
* @param {String} filename - Issue filename to analyze (relative/fullpath)
*/
function jsdec_main(filename) { // lgtm [js/unused-local-variable]
try {
// imports
var Printer = require('libdec/printer');
if (filename && !rzcmd) {
var jsonstr = read_file(filename).trim();
var data = rzutil.dataTestSuite(jsonstr);
Global.evars = new rzutil.evarsTestSuite(data);
Global.argdb = data.argdb;
Global.printer = new Printer();
var architecture = libdec.archs[data.arch];
Global.context = new libdec.context();
// af seems to break renaming.
/* asm.pseudo breaks things.. */
if (data.graph && data.graph.length > 0) {
var p = new libdec.core.session(data, architecture);
var arch_context = architecture.context(data);
libdec.core.analysis.pre(p, architecture, arch_context);
libdec.core.decompile(p, architecture, arch_context);
libdec.core.analysis.post(p, architecture, arch_context);
libdec.core.print(p);
Global.printer.flushOutput(Global.context.lines, Global.context.errors, Global.context.log, Global.evars.extra);
} else {
console.log('Error: no data available.\nPlease analyze the function/binary first.');
}
} else {
console.log('missing JSON to test.');
}
} catch (e) {
console.log('Exception:', e.stack);
}
}
-182
View File
@@ -1,182 +0,0 @@
// SPDX-FileCopyrightText: 2020-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
const Long = require('libdec/long');
const rzutil = require('libdec/rzutil');
const Strings = require('libdec/core/strings');
const Functions = require('libdec/core/functions');
const Extra = require('libdec/core/extra');
const _re_keywords = /\bif\b|\belse\b|\bwhile\b|\bfor\b|\bdo\b|\breturn\b|\bthrow\b|\bnew\b|\b__asm\b/g;
const _re_types = /\b[ui]+nt[123468]+_t\b|\bvoid\b|\bconst\b|\bsizeof\b|\bfloat\b|\bdouble\b|\bchar\b|\bwchar_t\b|\bextern\b|\bstruct\b|\bsize_t\b|\btime_t\b|\bboolean\b/g;
const _re_numbers = /\b0x[0-9a-fA-F]+\b|\b\d+\b/g;
const _re_string = /"[^"]+"/;
const _re_objcall = /[\w.]+\s?\([^)]+\)|[\w.]+\s?\(\)/;
function Annotation(start, length, value, pointer, type, syntax_type) {
this.start = start;
this.end = start + length;
this.type = type;
if (["function_name", "function_parameter", "local_variable"].indexOf(this.type) >= 0) {
this.name = value;
}
if (["function_name", "offset", "global_variable", "constant_variable"].indexOf(this.type) >= 0) {
this.offset = pointer.toString();
}
if (this.type == "syntax_highlight") {
this.syntax_highlight = syntax_type;
}
}
function _sort_by_start(x, y) {
if (x.start == y.start) {
if (x.type == "offset") {
return -1;
} else if (x.type == "syntax_highlight") {
return 0;
}
return 1;
}
return x.start - y.start;
}
function _match_annotation(regex, line, callback) {
var tokens, matches;
matches = line.match(regex);
tokens = line.split(regex);
if (!matches) {
return;
}
for (var i = 0, pos = 0; i < matches.length; i++) {
pos += tokens[i].length;
callback(pos, matches[i]);
pos += matches[i].length;
}
}
return {
context: function() {
var data = new rzutil.data(false);
return {
comment: false,
arch: data.arch,
strings: new Strings(data.xrefs.strings, true).data,
functions: new Functions(data.xrefs.functions, true).data.map(function(x) {
return {
location: x.offset,
value: Extra.replace.call(x.name),
name: x.name
};
}),
variables: data.arch == "dalvik" ? [] : Array.prototype.concat(data.xrefs.arguments.stack, data.xrefs.arguments.reg)
};
},
parse: function(current, line, context) {
var pos, old, i, a = [],
it, tmp, ll = line.str.length;
var string_beg = ll,
string_end = -1;
a.push(new Annotation(current, ll, null, line.offset, "offset"));
if (line.str.trim().startsWith('/*') || context.comment) {
context.comment = !line.str.endsWith('*/');
a.push(new Annotation(current, ll, line.str, null, "syntax_highlight", "comment"));
return a;
} else if (line.str.startsWith('//')) {
a.push(new Annotation(current, ll, line.str, null, "syntax_highlight", "comment"));
return a;
} else if (line.str.startsWith('#')) {
a.push(new Annotation(current, ll, line.str, null, "syntax_highlight", "comment"));
return a;
}
/* strings */
for (i = context.strings.length - 1; i >= 0; i--) {
it = context.strings[i];
var str = '"' + it.value + '"';
pos = line.str.indexOf(str);
if (pos > 0) {
// include the ""
a.push(new Annotation(current + pos, str.length, str, it.location, "global_variable", null));
a.push(new Annotation(current + pos, str.length, str, null, "syntax_highlight", "global_variable"));
string_beg = pos;
string_end = string_beg + str.length;
break;
}
}
/* strings with regex */
if (string_end < 0) {
tmp = line.str.match(_re_string) || [];
for (i = tmp.length - 1, old = 0; i >= 0; i--) {
pos = line.str.indexOf(tmp[i]);
a.push(new Annotation(current + pos, tmp[i].length, tmp[i], null, "syntax_highlight", "global_variable"));
string_beg = pos;
string_end = pos + tmp[i].length;
break;
}
}
/* function names */
if (context.arch == "dalvik") {
pos = line.str.search(_re_objcall);
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
var callname = line.str.substr(pos, line.str.substr(pos).indexOf('(')).trim();
if (['__asm'].indexOf(callname) < 0) {
a.push(new Annotation(current + pos, callname.length, callname, null, "syntax_highlight", "function_name"));
}
}
} else {
for (i = context.functions.length - 1; i >= 0; i--) {
it = context.functions[i];
pos = line.str.search(new RegExp('\\b' + it.value + '\\b'));
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, it.value.length, it.name, it.location, "function_name", null));
a.push(new Annotation(current + pos, it.value.length, it.value, null, "syntax_highlight", "function_name"));
break;
}
}
}
/* variables */
for (i = context.variables.length - 1, old = 0; i >= 0; i--) {
it = context.variables[i];
pos = it.type.match(_re_types) ? -1 : line.str.search(new RegExp('\\b' + it.type + '\\b'));
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, it.type.length, it.type, null, "syntax_highlight", "datatype"));
}
pos = line.str.search(new RegExp('\\b' + it.name + '\\b'));
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
var type = (it.kind === 'arg' || it.kind === 'reg') ? "function_parameter" : "local_variable";
a.push(new Annotation(current + pos, it.name.length, it.name, line.offset, type, null));
a.push(new Annotation(current + pos, it.name.length, it.name, null, "syntax_highlight", type));
}
}
/* keywords */
_match_annotation(_re_keywords, line.str, function(pos, match) {
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, match.length, match, null, "syntax_highlight", "keyword"));
}
});
/* numbers */
_match_annotation(_re_numbers, line.str, function(pos, match) {
if (match.length > 1 && match.charAt(0) == '0' && match.charAt(1) != 'x') {
return;
}
if (match != '0') {
pos = old + line.str.substr(old, ll).indexOf(match);
} else {
pos = old + line.str.substr(old, ll).search(/\b0\b/);
}
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
var location = Long.fromString(match);
a.push(new Annotation(current + pos, match.length, match, location, "constant_variable", null));
a.push(new Annotation(current + pos, match.length, match, null, "syntax_highlight", "constant_variable"));
}
});
/* types */
_match_annotation(_re_types, line.str, function(pos, match) {
if (pos >= 0 && !(pos >= string_beg && pos <= string_end)) {
a.push(new Annotation(current + pos, match.length, match, null, "syntax_highlight", "datatype"));
}
});
return a.sort(_sort_by_start);
}
};
});
-389
View File
@@ -1,389 +0,0 @@
// SPDX-FileCopyrightText: 2019-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
const Base = require('libdec/core/base');
const Variable = require('libdec/core/variable');
//const Extra = require('libdec/core/extra');
const _REG = {
X: 'x',
Y: 'y',
stackptr: 'SP',
accumulator: 'acc',
carry: 'C',
overflow: 'V',
decimal: 'D',
interrupt: 'I',
zero: 'Z',
};
function _arg(instr, idx) {
var o = instr.parsed.opd;
if (idx > 0) {
return o[idx];
}
o = o[0];
if (o.immediate) {
return o.token;
}
return Variable.pointer(o.token, 16, false);
}
function _math(op, instr, bits) {
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
if (!srcB) {
return op(_REG.accumulator, _REG.accumulator, srcA, bits);
}
return Base.composed([
op(_REG.accumulator, _REG.accumulator, srcA, bits),
Base.add(_REG.accumulator, _REG.accumulator, srcB),
]);
}
function _math_rotate(op, instr, bits) {
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
if (!srcB) {
// destination, source_a, source_b, bits
return op(_REG.accumulator, srcA, bits, 16);
}
return Base.composed([
op(_REG.accumulator, srcA, bits, 16),
Base.add(_REG.accumulator, _REG.accumulator, srcB),
]);
}
function _load(instr, register, bits) {
bits = bits || 16;
register = register || _REG.accumulator;
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
var ops = [];
if (typeof srcA == "string") {
// pointer, register, bits, is_signed
ops.push(Base.read_memory(register, register, srcA, bits));
} else {
ops.push(Base.assign(register, srcA));
}
if (!srcB) {
return ops[0];
}
ops.push(Base.add(register, register, srcB));
return Base.composed(ops);
}
function _store(instr, register, bits) {
bits = bits || 16;
register = register || _REG.accumulator;
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
var ops = [];
if (typeof srcA == "string") {
// pointer, register, bits, is_signed
ops.push(Base.write_memory(register, register, srcA, bits));
} else {
ops.push(Base.assign(srcA, register));
}
if (!srcB) {
return ops[0];
}
ops.push(Base.add(register, register, srcB));
return Base.composed(ops);
}
function _nop(instr, context, instructions) {
return Base.nop();
}
return {
instructions: {
adc: function(instr) {
return _math(Base.add, instr);
},
and: function(instr) {
return _math(Base.and, instr);
},
asl: function(instr) {
return _math(Base.shift_left, instr, 1);
},
bit: function(instr, context) {
var p = _arg(instr, 0);
context.cond.a = '(' + _REG.accumulator + ' & ' + p + ')';
context.cond.b = '0';
return Base.nop();
},
bcc: function(instr, context) {
instr.conditional(_REG.carry, 0, 'EQ');
return Base.nop();
},
bcs: function(instr, context) {
instr.conditional(_REG.carry, 0, 'NE');
return Base.nop();
},
beq: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'EQ');
return Base.nop();
},
bmi: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'LT');
return Base.nop();
},
bne: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'NE');
return Base.nop();
},
bpl: function(instr, context) {
instr.conditional(context.cond.a, context.cond.b, 'GT');
return Base.nop();
},
brk: function(instr, context) {
Global.context.addMacro('#define INTERRUPT() __asm(brk)');
return Base.call(Variable.macro('INTERRUPT'), []);
},
bvc: function(instr, context) {
instr.conditional(_REG.overflow, 0, 'EQ');
return Base.nop();
},
bvs: function(instr, context) {
instr.conditional(_REG.overflow, 0, 'NE');
return Base.nop();
},
clc: function(instr, context) {
return Base.assign(_REG.carry, '0');
},
cld: function(instr, context) {
return Base.assign(_REG.decimal, '0');
},
cli: function(instr, context) {
return Base.assign(_REG.interrupt, '0');
},
clv: function(instr, context) {
return Base.assign(_REG.overflow, '0');
},
cmp: function(instr, context) {
instr.setBadJump();
context.cond.a = _REG.accumulator;
var srcA = _arg(instr, 0);
var srcB = _arg(instr, 1);
if (!srcB) {
context.cond.b = srcA;
return Base.nop();
}
var v = Variable.uniqueName();
context.cond.b = v;
return Base.add(v, srcA, srcB);
},
cpx: function(instr, context) {
instr.setBadJump();
context.cond.a = _REG.X;
context.cond.b = _arg(instr, 0);
return Base.nop();
},
cpy: function(instr, context) {
instr.setBadJump();
context.cond.a = _REG.Y;
context.cond.b = _arg(instr, 0);
return Base.nop();
},
dec: function(instr, context) {
var p = _arg(instr, 0);
context.cond.a = p;
context.cond.b = '0';
return Base.subtract(p, p, 1);
},
dex: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.subtract(_REG.X, _REG.X, 1);
},
dey: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
return Base.subtract(_REG.Y, _REG.Y, 1);
},
eor: function(instr, context) {
return _math(Base.xor, instr);
},
inc: function(instr, context) {
var p = _arg(instr, 0);
context.cond.a = p;
context.cond.b = '0';
return Base.add(p, p, 1);
},
inx: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.add(_REG.X, _REG.X, 1);
},
iny: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
return Base.add(_REG.Y, _REG.Y, 1);
},
jmp: _nop,
jsr: function(instr) {
var p = instr.parsed.opd[0].token;
if (p.startsWith('0x')) {
p = Variable.functionPointer(p);
}
return Base.call(p);
},
lda: function(instr, context) {
context.cond.a = _REG.accumulator;
context.cond.b = '0';
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(_REG.accumulator, instr.parsed.opd[0].token.replace(/^sym\./, ''));
}
return _load(instr, _REG.accumulator, 16);
},
ldx: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(_REG.X, instr.parsed.opd[0].token.replace(/^sym\./, ''));
}
return _load(instr, _REG.X, 16);
},
ldy: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(_REG.Y, instr.parsed.opd[0].token.replace(/^sym\./, ''));
}
return _load(instr, _REG.Y, 16);
},
lsr: function(instr) {
return _math(Base.shift_right, instr, 1);
},
ora: function(instr, context) {
return _math(Base.xor, instr);
},
pha: _nop,
php: _nop,
pla: _nop,
plp: _nop,
rol: function(instr) {
return _math_rotate(Base.rotate_left, instr, 1);
},
ror: function(instr) {
return _math_rotate(Base.rotate_right, instr, 1);
},
rti: function(instr) {
return Base.return();
},
rts: function(instr) {
return Base.return();
},
sbc: function(instr) {
return _math(Base.subtract, instr);
},
sec: function(instr, context) {
return Base.assign(_REG.carry, 1);
},
sed: function(instr, context) {
return Base.assign(_REG.decimal, 1);
},
sei: function(instr, context) {
return Base.assign(_REG.interrupt, 1);
},
sta: function(instr) {
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(instr.parsed.opd[0].token.replace(/^sym\./, ''), _REG.accumulator);
}
return _store(instr, _REG.accumulator, 16);
},
stx: function(instr) {
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(instr.parsed.opd[0].token.replace(/^sym\./, ''), _REG.X);
}
return _store(instr, _REG.X, 16);
},
sty: function(instr) {
var o = instr.parsed.opd[0];
if (o.token.startsWith('sym.') || o.immediate) {
return Base.assign(instr.parsed.opd[0].token.replace(/^sym\./, ''), _REG.Y);
}
return _store(instr, _REG.Y, 16);
},
tax: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.assign(_REG.X, _REG.accumulator);
},
tay: function(instr, context) {
context.cond.a = _REG.Y;
context.cond.b = '0';
return Base.assign(_REG.Y, _REG.accumulator);
},
tsx: function(instr, context) {
context.cond.a = _REG.X;
context.cond.b = '0';
return Base.assign(_REG.X, _REG.stackptr);
},
txs: function(instr, context) {
return Base.assign(_REG.stackptr, _REG.X);
},
txa: function(instr, context) {
context.cond.a = _REG.accumulator;
context.cond.b = '0';
return Base.assign(_REG.accumulator, _REG.X);
},
tya: function(instr, context) {
context.cond.a = _REG.accumulator;
context.cond.b = '0';
return Base.assign(_REG.accumulator, _REG.Y);
},
nop: _nop,
invalid: _nop
},
parse: function(assembly) {
var tokens = assembly.trim().match(/^([\w]+) ?(#)?(\()?((0x[\da-fA-F]+)|([a-zA-Z0-9._]+))?(\))?(,([\w]+))?\)?$/);
var opds = [];
if (tokens[5] || tokens[6]) {
var token = tokens[5] || tokens[6];
if (tokens[3] == '(' && tokens[7] == ')' && tokens[9]) {
token += ' + ' + tokens[9];
}
opds.push({
immediate: tokens[2] == '#',
pointer: tokens[3] == '(',
token: token,
});
}
if (tokens[9] && tokens[3] == '(' && tokens[7] != ')') {
opds.push(tokens[9]);
}
return {
mnem: tokens[1],
opd: opds
};
},
context: function() {
return {
cond: {
a: _REG.accumulator,
b: '?',
}
};
},
preanalisys: function(instructions, context) {},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
});
-279
View File
@@ -1,279 +0,0 @@
// SPDX-FileCopyrightText: 2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
const Base = require('libdec/core/base');
const Variable = require('libdec/core/variable');
const EXTRAM = "eram + ";
const INDRAM = "iram + ";
function resolve_opd(instr, index) {
var a = instr.parsed.opd[index].replace(/\+/, ' + ');
if (a.indexOf('#') == 0) {
return a.substr(1, a.length);
} else if (a.match(/^\d+$|^0x[a-fA-F\d]+$/)) {
return Variable.pointer(INDRAM + a, 8, false);
} else if (a.indexOf('@') == 0) {
return Variable.pointer(EXTRAM + a.substr(1, a.length), 8, false);
}
return a;
}
function previous(instr, instructions) {
return instructions[instructions.indexOf(instr) - 1];
}
function is_mnem(instr, mnem, startswith) {
if (startswith) {
return instr && instr.parsed.mnem.indexOf(mnem) == 0;
}
return instr && instr.parsed.mnem == mnem;
}
function is_last(instr, instructions) {
return instructions.indexOf(instr) == (instructions.length - 1);
}
function is_membit(instr, index) {
return instr.parsed.opd[index].indexOf('.') > 0;
}
function write_membit(instr, index, b) {
var a = instr.parsed.opd[index].split('.');
var p = Variable.pointer(a[0], 8, false);
if (b == '1') {
b = '0x' + (1 << parseInt(a[1])).toString(16);
} else if (b != '0') {
b = '(' + b + ' & 1)' + (parseInt(a[1]) > 0 ? ' << ' + a[1] : '');
} else {
var bit = parseInt(a[1]) < 1 ? '~1' : '~(1 << ' + a[1] + ')';
return Base.and(p, p, bit);
}
return Base.or(p, p, b);
}
function read_membit(instr, index, b) {
var a = instr.parsed.opd[index].split('.');
var p = Variable.pointer(a[0], 8, false);
if (parseInt(a[1]) < 1) {
return Base.and(b, p, '1');
}
return Base.assign(b, '(' + p.toString() + ' >> ' + a[1] + ') & 1');
}
function _mov(instr, context, instructions) {
if (is_membit(instr, 0)) {
return write_membit(instr, 0, resolve_opd(instr, 1));
} else if (is_membit(instr, 1)) {
return read_membit(instr, 1, resolve_opd(instr, 0));
}
var a = resolve_opd(instr, 0);
var b = resolve_opd(instr, 1);
return Base.assign(a, b);
}
function _call(instr, context, instructions) {
var args = [];
var prev = previous(instr, instructions);
if (prev && prev.parsed.opd[0] == 'a') {
args.push(prev.parsed.opd[0]);
}
return Base.call(instr.parsed.opd[0], args);
}
function _jump(instr, context, instructions) {
if (is_last(instr, instructions) &&
(instr.jump.gt(instr.location) || instr.jump.lt(instructions[0].location))) {
return _call(instr, context, instructions);
}
return Base.nop();
}
function _math(instr, context, op, carry) {
if (carry) {
return op('a', op(resolve_opd(instr, 0), resolve_opd(instr, 1)), 'carry');
}
return op('a', resolve_opd(instr, 0), resolve_opd(instr, 1));
}
function _nop(instr, context, instructions) {
return Base.nop();
}
return {
instructions: {
acall: _call,
add: function(instr, context, instructions) {
return _math(instr, context, Base.add);
},
addc: function(instr, context, instructions) {
instr.comments.push("add with carry");
return _math(instr, context, Base.add, true);
},
ajmp: _jump,
anl: function(instr, context, instructions) {
return _math(instr, context, Base.and);
},
cjne: function(instr, context, instructions) {
instr.conditional(resolve_opd(instr, 0), resolve_opd(instr, 1), 'NE');
return Base.nop();
},
clr: function(instr, context, instructions) {
if (is_membit(instr, 0)) {
return write_membit(instr, 0, '0');
}
return Base.assign(resolve_opd(instr, 0), '0');
},
cpl: function(instr, context, instructions) {
return Base.not(instr.parsed.opd[0], instr.parsed.opd[0]);
},
dec: function(instr, context, instructions) {
return Base.decrease(resolve_opd(instr, 0), '1');
},
div: function(instr, context, instructions) {
return Base.divide('a', 'a', 'b');
},
djnz: function(instr, context, instructions) {
var a = resolve_opd(instr, 0);
instr.conditional(a, '0', 'NE');
return Base.decrease(a, '1');
},
inc: function(instr, context, instructions) {
return Base.increase(resolve_opd(instr, 0), '1');
},
jb: function(instr, context, instructions) {
instr.conditional('b', '0', 'NE');
return Base.nop();
},
jbc: function(instr, context, instructions) {
instr.conditional('b', '0 && c', 'NE');
return Base.nop();
},
jc: function(instr, context) {
instr.conditional('c', '0', 'NE');
return Base.nop();
},
jmp: _jump,
jnb: function(instr, context, instructions) {
instr.conditional('b', '0', 'EQ');
return Base.nop();
},
jnc: function(instr, context, instructions) {
instr.conditional('c', '0', 'EQ');
return Base.nop();
},
jnz: function(instr, context, instructions) {
var p = previous(instr, instructions);
instr.conditional(is_mnem(p, 'mov', true) ? resolve_opd(p, 1) : 'a', '0', 'NE');
return Base.nop();
},
jz: function(instr, context, instructions) {
var p = previous(instr, instructions);
instr.conditional(is_mnem(p, 'mov', true) ? resolve_opd(p, 1) : 'a', '0', 'EQ');
return Base.nop();
},
lcall: _call,
ljmp: _jump,
mov: _mov,
movc: _mov,
movx: _mov,
mul: function(instr, context, instructions) {
return Base.multiply('a', 'a', 'b');
},
orl: function(instr, context, instructions) {
return _math(instr, context, Base.or);
},
pop: function(instr) {
return Base.assign(resolve_opd(instr, 0), Base.call('pop', []));
},
push: function(instr) {
return Base.call('push', [resolve_opd(instr, 0)]);
},
ret: function(instr) {
return Base.return();
},
reti: function(instr) {
return Base.return();
},
rl: function(instr) {
return Base.rotate_left('a', 'a', '1', 8);
},
rlc: function(instr) {
instr.comments.push("rotate with carry");
return Base.rotate_left('a', 'a', '1', 8);
},
rr: function(instr) {
return Base.rotate_right('a', 'a', '1', 8);
},
rrc: function(instr) {
instr.comments.push("rotate with carry");
return Base.rotate_right('a', 'a', '1', 8);
},
setb: function(instr, context, instructions) {
if (is_membit(instr, 0)) {
return write_membit(instr, 0, '1');
}
return Base.assign(instr.parsed.opd[0], 1);
},
sjmp: _jump,
subb: function(instr, context, instructions) {
return _math(instr, context, Base.subtract);
},
swap: function(instr, context, instructions) {
return Base.swap_endian(resolve_opd(instr, 1), resolve_opd(instr, 0), 8);
},
xch: function(instr, context, instructions) {
return Base.swap(resolve_opd(instr, 0), resolve_opd(instr, 1), 8);
},
xchd: function(instr, context, instructions) {
var a = resolve_opd(instr, 0);
var b = resolve_opd(instr, 1);
var tmp = Variable.uniqueName('tmp');
var ops = [
Base.and(tmp, a, '0xF'),
Base.and(a, a, '0xF0'),
Base.or(a, b, '0xF0'),
Base.and(b, b, '0xF0'),
Base.or(b, b, tmp),
];
context.local.push(tmp);
return Base.composed(ops);
},
xrl: function(instr, context, instructions) {
return _math(instr, context, Base.xor);
},
nop: _nop,
reserved: _nop,
invalid: _nop
},
parse: function(assembly) {
assembly = assembly.trim().replace(/,/g, '');
var tokens = assembly.split(' ');
return {
mnem: tokens[0],
opd: tokens.splice(1)
};
},
context: function() {
return {
local: []
};
},
preanalisys: function(instructions, context) {},
localvars: function(context) {
return context.local.map(function(x) {
return 'uint8_t ' + x;
});
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
});
-1864
View File
File diff suppressed because it is too large. Load diff
-676
View File
@@ -1,676 +0,0 @@
// SPDX-FileCopyrightText: 2018-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
var Variable = require('libdec/core/variable');
var Base = require('libdec/core/base');
const AVR_MEM_BITS = 16;
const AVR_X_MACRONAME = 'MEM_X';
const AVR_Y_MACRONAME = 'MEM_Y';
const AVR_Z_MACRONAME = 'MEM_Z';
const AVR_X_MACRO = '#define ' + AVR_X_MACRONAME + ' ((uint16_t*)((r27 << 8) | r26))';
const AVR_Y_MACRO = '#define ' + AVR_Y_MACRONAME + ' ((uint16_t*)((r29 << 8) | r28))';
const AVR_Z_MACRO = '#define ' + AVR_Z_MACRONAME + ' ((uint16_t*)((r31 << 8) | r30))';
const AVR_MEMORY = {
'x': {
name: AVR_X_MACRONAME,
macro: AVR_X_MACRO,
high: 'r27',
low: 'r26'
},
'y': {
name: AVR_Y_MACRONAME,
macro: AVR_Y_MACRO,
high: 'r29',
low: 'r28'
},
'z': {
name: AVR_Z_MACRONAME,
macro: AVR_Z_MACRO,
high: 'r31',
low: 'r30'
}
};
var AVR_CTR = 0;
var _to_16bit = function(high, low) {
if ((high == '0x00' || high == '0') && (low == '0x00' || low == '0')) {
return '0';
} else if (low == '0x00' || low == '0') {
return '(' + high + ' << 8)';
} else if (high == '0x00' || high == '0') {
return low;
}
return '(' + low + ' | (' + high + ' << 8))';
};
var _common_math = function(instr, op) {
instr.setBadJump();
var e = instr.parsed.opd;
return op(e[0], e[0], e[1]);
};
var _compare = function(a, b, context) {
context.cond.a = a;
context.cond.b = b;
};
var _compare_values = function(a1, b1, a2, b2, context) {
context.cond.a = _to_16bit(a2, a1);
context.cond.b = _to_16bit(b2, b1);
};
var _compare_bytes = function(a, b, context) {
var a1 = context.cond.a;
var b1 = context.cond.b;
_compare_values(a1, b1, a, b, context);
};
var _conditional = function(instr, context, type) {
instr.conditional(context.cond.a, context.cond.b, type);
if (context.cond.instr) {
context.cond.instr.valid = false;
}
};
var _next_register = function(reg) {
var num = parseInt(reg.substr(1, reg.length)) + 1;
return 'r' + num;
};
var _returns_r0 = function(instr, context, inverted) {
if (inverted && instr.parsed.opd[1] == 'r0') {
context.returns = 'r0';
} else if (!inverted && instr.parsed.opd[0] == 'r0') {
context.returns = 'r0';
}
};
var _conditional_next = function(instr, context, instructions, type) {
instr.conditional(context.cond.a, context.cond.b, type);
var next = instructions[instructions.indexOf(instr) + 1];
if (next) {
instr.jump = next.location;
}
if (context.cond.instr) {
context.cond.instr.valid = false;
}
};
var _load16 = function(instr, context) {
var v, m, op;
_returns_r0(instr, context);
var ptr = instr.parsed.opd[1];
if (ptr.indexOf('-') >= 0) {
ptr = ptr.replace('-', '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.read_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[0], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.subtract(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '-')
];
op = Base.composed(m);
Global.context.addMacro(AVR_MEMORY[ptr].macro);
return op;
} else if (ptr.indexOf('+') >= 0) {
ptr = ptr.replace('+', '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.read_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[0], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.add(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '+')
];
op = Base.composed(m);
Global.context.addMacro(AVR_MEMORY[ptr].macro);
return op;
}
//pointer, register, bits, is_signed
op = Base.read_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[0], 8, false);
Global.context.addMacro(AVR_MEMORY[ptr].macro);
return op;
};
var _store16 = function(instr, context) {
var v, m, op;
instr.setBadJump();
_returns_r0(instr, context);
var ptr = instr.parsed.opd[0];
if (ptr.indexOf('-') >= 0) {
ptr = ptr.replace(/-\d?/, '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.write_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[1], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.subtract(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '-')
];
op = Base.composed(m);
Global.context.addMacro(AVR_MEMORY[ptr].macro);
return op;
} else if (ptr.indexOf('+') >= 0) {
ptr = ptr.replace(/\+\d?/, '');
v = Variable.uniqueName('local');
//pointer, register, bits, is_signed
m = [
Base.write_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[1], 8, false),
Base.assign('uint8_t ' + v, AVR_MEMORY[ptr].low),
Base.add(AVR_MEMORY[ptr].low, AVR_MEMORY[ptr].low, 1),
Base.conditional_math(AVR_MEMORY[ptr].high, AVR_MEMORY[ptr].low, v, 'LT', AVR_MEMORY[ptr].high, 1, AVR_MEMORY[ptr].high, '+')
];
op = Base.composed(m);
Global.context.addMacro(AVR_MEMORY[ptr].macro);
return op;
}
//pointer, register, bits, is_signed
op = Base.write_memory(AVR_MEMORY[ptr].name, instr.parsed.opd[1], 8, false);
Global.context.addMacro(AVR_MEMORY[ptr].macro);
return op;
};
return {
instructions: {
adc: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.add);
},
add: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.add);
},
adiw: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
var b = instr.parsed.opd[1];
var a1 = instr.parsed.opd[0];
var a2 = _next_register(instr.parsed.opd[0]);
_compare_values(a1, b, a2, b, context);
context.cond.instr = instr;
if (b == '0x00' || b == '0') {
return Base.nop();
}
var op1 = null;
var op2 = null;
if (b == '0x01' || b == '1') {
op1 = Base.increase(a1, '1');
op2 = Base.increase(a2, '1');
} else {
op1 = Base.add(a1, a1, b);
op2 = Base.add(a2, a2, b);
}
return Base.composed([op1, op2]);
},
and: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.and);
},
andi: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.and);
},
asr: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.shift_right(instr.parsed.opd[0], instr.parsed.opd[0], '1');
},
brbc: function(instr, context) {
_returns_r0(instr, context);
var old_b = context.cond.b;
context.cond.b = '0';
_conditional(instr, context, 'NE');
context.cond.b = old_b;
return Base.nop();
},
brbs: function(instr, context) {
_returns_r0(instr, context);
var old_b = context.cond.b;
context.cond.b = '(1 << ' + instr.parsed.opd[0] + ')';
_conditional(instr, context, 'NE');
context.cond.b = old_b;
return Base.nop();
},
brcc: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'GE');
return Base.nop();
},
brcs: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
breq: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'EQ');
return Base.nop();
},
brlo: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
brlt: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
brmi: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LT');
return Base.nop();
},
brne: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'NE');
return Base.nop();
},
brpl: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'GT');
return Base.nop();
},
brsh: function(instr, context) {
_returns_r0(instr, context);
_conditional(instr, context, 'LE');
return Base.nop();
},
bset: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.macro('SREG_SET_BIT (' + instr.parsed.opd[0] + ')', '#define SREG_SET_BIT(x) __asm(bset (x))');
},
call: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
//name, args, is_pointer, returns, bits
if (instr.parsed.opd[0].indexOf('0x') == 0) {
return Base.call(Variable.functionPointer(instr.parsed.opd[0], 16), []);
}
return Base.call(instr.parsed.opd[0], []);
},
cli: function(instr) {
instr.setBadJump();
return Base.macro('DISABLE_INTERRUPTS', '#define DISABLE_INTERRUPTS __asm(cli)');
},
clr: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], '0');
},
clt: function(instr) {
instr.setBadJump();
return Base.macro('CLEAR_TRANSFER_FLAG', '#define CLEAR_TRANSFER_FLAG __asm(clt)');
},
com: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.subtract(instr.parsed.opd[0], '0xff', instr.parsed.opd[0]);
},
cp: function(instr, context) {
instr.setBadJump();
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return Base.nop();
},
cpc: function(instr, context, instructions) {
instr.setBadJump();
var p = instructions.indexOf(instr);
if (instructions[p - 1] && instructions[p - 1].parsed.mnem.indexOf('cp') == 0) {
_compare_bytes(instr.parsed.opd[0], instr.parsed.opd[1], context);
} else {
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
}
context.cond.instr = instr;
return Base.nop();
},
cpi: function(instr, context) {
instr.setBadJump();
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return Base.nop();
},
dec: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
_compare('--' + instr.parsed.opd[0], '0', context);
context.cond.instr = instr;
return Base.decrease(instr.parsed.opd[0], '1');
},
eor: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.xor);
},
icall: function(instr, context) {
_returns_r0(instr, context);
instr.setBadJump();
//name, args, is_pointer, returns, bits
var op = Base.call(Variable.functionPointer(AVR_MEMORY.z.name), []);
Global.context.addMacro(AVR_MEMORY.z.macro);
return op;
},
ijmp: function(instr, context) {
_returns_r0(instr, context);
instr.setBadJump();
var op = Base.goto(AVR_MEMORY.z.name);
Global.context.addMacro(AVR_MEMORY.z.macro);
return op;
},
in: function(instr, context) {
_returns_r0(instr, context);
var e = instr.parsed.opd;
return Base.macro('READ_FROM_IO (' + e[1] + ', ' + e[0] + ')', '#define READ_FROM_IO(x,y) __asm(in (y), (x))');
},
inc: function(instr, context) {
_returns_r0(instr, context);
_compare('++' + instr.parsed.opd[0], '0', context);
context.cond.instr = instr;
return Base.increase(instr.parsed.opd[0], '1');
},
iret: function(instr) {
return Base.macro('RETURN_FROM_INTERRUPT', '#define RETURN_FROM_INTERRUPT __asm(iret)');
},
jmp: function(instr, context) {
return Base.nop();
},
ld: _load16,
ldd: function(instr, context) {
_returns_r0(instr, context);
var ptr = instr.parsed.opd[1].match(/([xyz]|[+-0-9]+)/g);
var offset = ptr[1].replace(/(-)/, ' - ').replace(/(\+)/, ' + ');
//pointer, register, bits, is_signed
var op = Base.read_memory(AVR_MEMORY[ptr[0]].name + offset, instr.parsed.opd[0], 8, false);
Global.context.addMacro(AVR_MEMORY[ptr[0]].macro);
return op;
},
ldi: function(instr, context) {
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], instr.parsed.opd[1]);
},
lds: function(instr, context) {
_returns_r0(instr, context);
//pointer, register, bits, is_signed
return Base.read_memory(instr.parsed.opd[1], instr.parsed.opd[0], 8, false);
},
lpm: _load16,
lsl: function(instr, context) {
_returns_r0(instr, context);
return Base.shift_left(instr.parsed.opd[0], instr.parsed.opd[0], '1');
},
lsr: function(instr, context) {
_returns_r0(instr, context);
return Base.shift_right(instr.parsed.opd[0], instr.parsed.opd[0], '1');
},
mov: function(instr, context) {
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], instr.parsed.opd[1]);
},
movw: function(instr, context) {
_returns_r0(instr, context);
var a1 = instr.parsed.opd[0];
var a2 = _next_register(instr.parsed.opd[0]);
var b1 = instr.parsed.opd[1];
var b2 = _next_register(instr.parsed.opd[1]);
var op1 = Base.assign(a1, b1);
var op2 = Base.assign(a2, b2);
return Base.composed([op1, op2]);
},
mul: function(instr, context) {
context.returns = 'r0';
var name = 'value' + (++AVR_CTR);
var ops = [];
ops.push(Base.multiply('uint16_t ' + name, instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.assign('r0', '(' + name + ' & 0xFF)'));
ops.push(Base.assign('r1', '(' + name + ' >> 8)'));
return Base.composed(ops);
},
muls: function(instr, context) {
context.returns = 'r0';
var name = 'value' + (++AVR_CTR);
var ops = [];
ops.push(Base.multiply('int16_t ' + name, instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.assign('r0', '(' + name + ' & 0xFF)'));
ops.push(Base.assign('r1', '(' + name + ' >> 8)'));
return Base.composed(ops);
},
mulsu: function(instr, context) {
context.returns = 'r0';
var name = 'value' + (++AVR_CTR);
var ops = [];
ops.push(Base.multiply('uint16_t ' + name, instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.assign('r0', '(' + name + ' & 0xFF)'));
ops.push(Base.assign('r1', '(' + name + ' >> 8)'));
return Base.composed(ops);
},
neg: function(instr, context) {
_returns_r0(instr, context);
return Base.negate(instr.parsed.opd[0], instr.parsed.opd[0]);
},
nop: function(instr) {
instr.setBadJump();
return Base.nop();
},
not: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.not(instr.parsed.opd[0], instr.parsed.opd[0]);
},
or: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.or);
},
ori: function(instr, context) {
_returns_r0(instr, context);
return _common_math(instr, Base.or);
},
out: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context, true);
var e = instr.parsed.opd;
return Base.macro('WRITE_TO_IO (' + e[0] + ', ' + e[1] + ')', '#define WRITE_TO_IO(x,y) __asm(in (x), (y))');
},
pop: function(instr, context) {
instr.setBadJump();
if (instr.parsed.opd[0] == 'r0') {
// if pops an r0, then the return value is void.
context.returns = null;
}
return Base.nop();
},
push: function(instr, context) {
instr.setBadJump();
return Base.nop();
},
rcall: function(instr, context) {
_returns_r0(instr, context);
return Base.call(Variable.functionPointer(instr.parsed.opd[0], AVR_MEM_BITS), []);
},
ret: function(instr, context) {
_returns_r0(instr, context);
// returns r1:r0
// but if pop r0 then return void.
return Base.return(context.returns);
},
reti: function(instr) {
return Base.macro('RETURN_FROM_INTERRUPT', '#define RETURN_FROM_INTERRUPT __asm(reti)');
},
rjmp: function(instr, context) {
_returns_r0(instr, context);
return Base.nop();
},
rol: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.rotate_left(instr.parsed.opd[0], instr.parsed.opd[0], '1', 8);
},
ror: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.rotate_right(instr.parsed.opd[0], instr.parsed.opd[0], '1', 8);
},
sbc: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.subtract);
},
sbci: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.subtract);
},
sbiw: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
var b = instr.parsed.opd[1];
var a1 = instr.parsed.opd[0];
var a2 = _next_register(instr.parsed.opd[0]);
_compare_values(a1, b, a2, b, context);
context.cond.instr = instr;
if (b == '0x00' || b == '0') {
return Base.nop();
}
var op1 = null;
var op2 = null;
if (b == '0x01' || b == '1') {
op1 = Base.decrease(a1, '1');
op2 = Base.decrease(a2, '1');
} else {
op1 = Base.subtract(a1, a1, b);
op2 = Base.subtract(a2, a2, b);
}
return Base.composed([op1, op2]);
},
sbr: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.or(instr.parsed.opd[0], instr.parsed.opd[1]);
},
sbrc: function(instr, context, instructions) {
instr.setBadJump();
var next = instructions[instructions.indexOf(instr) + 1];
if (next) {
_compare('(' + instr.parsed.opd[0] + ' & (1 << ' + instr.parsed.opd[1] + '))', '0', context);
context.cond.instr = instr;
_conditional_next(next, context, instructions, 'EQ');
return Base.or(instr.parsed.opd[0], instr.parsed.opd[1]);
}
return Base.nop();
},
sbrs: function(instr, context, instructions) {
instr.setBadJump();
var next = instructions[instructions.indexOf(instr) + 1];
if (next) {
_compare('(' + instr.parsed.opd[0] + ' & (1 << ' + instr.parsed.opd[1] + '))', '1', context);
context.cond.instr = instr;
_conditional_next(next, context, instructions, 'EQ');
return Base.or(instr.parsed.opd[0], instr.parsed.opd[1]);
}
return Base.nop();
},
sei: function(instr) {
instr.setBadJump();
return Base.macro('ENABLE_INTERRUPTS', '#define ENABLE_INTERRUPTS __asm(sei)');
},
ser: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.assign(instr.parsed.opd[0], '0xff');
},
set: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
return Base.macro('SET_TRANSFER_FLAG', '#define SET_TRANSFER_FLAG __asm(set)');
},
st: _store16,
std: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
var ptr = instr.parsed.opd[0].match(/([xyz]|[+-0-9]+)/g);
var offset = ptr[1].replace(/(-)/, ' - ').replace(/(\+)/, ' + ');
//pointer, register, bits, is_signed
var op = Base.write_memory(AVR_MEMORY[ptr[0]].name + offset, instr.parsed.opd[1], 8, false);
Global.context.addMacro(AVR_MEMORY[ptr[0]].macro);
return op;
},
sts: function(instr, context) {
instr.setBadJump();
_returns_r0(instr, context);
//pointer, register, bits, is_signed
return Base.write_memory(instr.parsed.opd[0], instr.parsed.opd[1], 8, false);
},
sub: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
return _common_math(instr, Base.subtract);
},
subi: function(instr, context) {
_returns_r0(instr, context);
_compare(instr.parsed.opd[0], instr.parsed.opd[1], context);
context.cond.instr = instr;
if (instr.parsed.opd[1] == '0x00' || instr.parsed.opd[1] == '0') {
instr.setBadJump();
return Base.nop();
}
return _common_math(instr, Base.subtract);
},
tst: function(instr, context) {
instr.setBadJump();
_compare(instr.parsed.opd[0], '0', context);
context.cond.instr = instr;
},
wdr: function(instr, context) {
instr.setBadJump();
return Base.macro('CLEAR_WATCHDOG', '#define CLEAR_WATCHDOG __asm(wdr)');
},
invalid: function(instr) {
instr.setBadJump();
return Base.nop();
}
},
parse: function(asm) {
asm = asm.toLowerCase();
var ret = asm.replace(/\[|\]/g, ' ').replace(/,/g, ' ');
ret = ret.replace(/\{|\}/g, ' ').replace(/\s+/g, ' ');
ret = ret.trim().replace(/0x00/, '0').split(' ');
return {
mnem: ret.shift(),
opd: ret
};
},
context: function() {
return {
cond: {
a: null,
b: null,
instr: null
},
returns: null
};
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return context.returns == null ? 'void' : 'uint8_t';
}
};
});
File diff suppressed because it is too large. Load diff
-430
View File
@@ -1,430 +0,0 @@
// SPDX-FileCopyrightText: 2018-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
var Base = require('libdec/core/base');
var Variable = require('libdec/core/variable');
var _to_size = function(value) {
if (value == 'b') {
return 8;
} else if (value == 'w') {
return 16;
} else if (value == 'l') {
return 32;
}
return 0;
};
var _as_pointer = function(e, where, signed, ispointer) {
var arg = e.opd[where];
if (arg.pointer) {
if (arg.presub) {
var m = e.bits / 8;
if (m == 1) {
arg = Variable.pointer('--' + arg.pointer, e.bits, signed);
} else {
arg = Variable.pointer(arg.pointer + ' -= ' + m, e.bits, signed);
}
} else {
return Variable.pointer(arg.pointer, e.bits, signed);
}
} else if (ispointer && arg.register.indexOf('0x') == 0) {
var tokens = arg.register.replace(/\.([bwl])/, ' $1').split(' ');
arg = Variable.pointer(tokens[0], _to_size(tokens[1]), signed);
} else {
return arg.register;
}
return arg;
};
var _is_register = function(name) {
return name && name.match(/\b[acdsACDS][0-9ixIX]\b/);
};
var _common_math = function(e, op) {
var src = _as_pointer(e, 0, true);
var dst = _as_pointer(e, 1, true);
if (e.opd[1].postadd) {
return Base.composed([op(dst, dst, src), Base.add(e.opd[1].register, e.opd[1].register, '' + (e.bits / 8))]);
}
return op(dst, dst, src);
};
var _move = function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = _as_pointer(e, 0, true, true);
var dst = _as_pointer(e, 1, true, true);
return Base.assign(dst, src);
};
var _move_multiple = function(instr, context) {
instr.setBadJump();
var memory, pointer, postadd, register, op;
var e = instr.parsed;
var incr = (e.bits / 8).toString();
var ops = [];
if (e.opd[0].pointer) {
//movem.l -(a7), d2-d3/a2-a5
memory = _as_pointer(e, 0, false);
pointer = e.opd[0].register;
postadd = e.opd[0].postadd;
register = e.opd[1].register;
op = Base.read_memory;
} else {
//movem.l d2-d3/a2-a5, -(a7)
memory = _as_pointer(e, 1, false);
pointer = e.opd[1].register;
postadd = e.opd[1].postadd;
register = e.opd[0].register;
op = Base.write_memory;
}
var reg = register.split('/');
for (var i = 0; i < reg.length; i++) {
var prefix = reg[i].charAt(0);
var tmp = reg[i].replace(/[a-zA-Z]/g, '').split('-');
var start = tmp[0];
var end = tmp[1] || tmp[0];
for (var j = start; j <= end; j++) {
ops.push(op(memory, prefix + j, e.bits, false));
if (postadd) {
ops.push(Base.add(pointer, pointer, incr));
}
}
}
return Base.composed(ops);
};
var _compare = function(instr, context) {
instr.setBadJump();
context.cond.a = _as_pointer(instr.parsed, 1, false);
context.cond.b = _as_pointer(instr.parsed, 0, false);
return Base.nop();
};
var _conditional = function(instr, context, type, zero) {
instr.conditional(context.cond.a, context.cond.b, type);
return Base.nop();
};
var _bitmask = function(offset, size) {
var mask = 0;
for (var i = 0; i < size; i++) {
mask <<= 1;
mask |= 1;
}
return '0x' + ((mask << offset) >>> 0).toString(16);
};
return {
instructions: {
add: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.add);
},
addi: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.add);
},
addq: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.add);
},
and: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.and);
},
andi: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.and);
},
bftst: function(instr, context) {
instr.setBadJump();
var vals = instr.assembly.match(/(\w+)(?:{(\d+):(\d+)})/);
var mask = _bitmask(vals[2], vals[3]);
var test = Variable.local('(' + vals[1] + ' & ' + mask + ')');
context.cond.a = test;
context.cond.b = '0';
return Base.nop();
},
bne: function(instr, context) {
return _conditional(instr, context, 'NE');
},
beq: function(instr, context) {
return _conditional(instr, context, 'EQ');
},
bgt: function(instr, context) {
return _conditional(instr, context, 'GT');
},
bge: function(instr, context) {
return _conditional(instr, context, 'GE');
},
blt: function(instr, context) {
return _conditional(instr, context, 'LT');
},
ble: function(instr, context) {
return _conditional(instr, context, 'LE');
},
bra: function(instr, context) {
return Base.nop();
},
btst: function(instr, context) {
instr.setBadJump();
var and = instr.parsed.opd[0].register == '0x0' ? ' & 1)' : ' & (1 << ' + instr.parsed.opd[0].register + '))';
var test = Variable.local('(' + instr.parsed.opd[1].register + and);
context.cond.a = test;
context.cond.b = '0';
return Base.nop();
},
clr: function(instr, context) {
var e = instr.parsed;
var dst = _as_pointer(e, 0, false);
var op = Base.assign(dst, '0');
if (e.opd[0].postadd) {
var ptr_reg = e.opd[0].register;
return Base.composed([op, Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))]);
}
return op;
},
cmp: _compare,
cmpi: _compare,
eori: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.xor);
},
jsr: function(instr) {
var arg = _is_register(instr.parsed.opd[0].register) ? Variable.functionPointer(instr.parsed.opd[0].register) : instr.parsed.opd[0].register;
return Base.call(arg, []);
},
lea: function(instr, context) {
instr.setBadJump();
var src = instr.string ? Variable.string(instr.string) : _as_pointer(instr.parsed, 0, false, true);
var dst = _as_pointer(instr.parsed, 1, false, true);
return Base.assign(dst, src);
},
link: function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = e.opd[0].register;
var dst = e.opd[1].register;
return Base.write_memory(dst == '0x0' ? 'a7' : ('a7 + ' + dst), src, e.bits, false);
},
lsl: function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = _as_pointer(e, 0, false);
var dst = _as_pointer(e, 1, false);
if (!e.opd[1]) {
return Base.shift_left(dst, dst, '1');
} else if (e.opd[1].pointer) {
var op = Base.shift_left(dst, dst, src);
if (e.opd[1].postadd) {
var ptr_reg = e.opd[1].register;
return Base.composed([op, Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))]);
}
return op;
}
return Base.shift_left(dst, dst, src);
},
lsr: function(instr) {
instr.setBadJump();
var e = instr.parsed;
var src = _as_pointer(e, 0, false);
var dst = _as_pointer(e, 1, false);
if (!e.opd[1]) {
return Base.shift_right(dst, dst, '1');
} else if (e.opd[1].pointer) {
var op = Base.shift_right(dst, dst, src);
if (e.opd[1].postadd) {
var ptr_reg = e.opd[1].register;
return Base.composed([op, Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))]);
}
return op;
}
return Base.shift_right(dst, dst, src);
},
move: function(instr) {
instr.setBadJump();
var ptr_reg, ops;
var e = instr.parsed;
var pointer = _as_pointer(e, 0, false, true);
var register = _as_pointer(e, 1, false, true);
if (e.opd[1].postadd) {
ptr_reg = e.opd[1].register;
ops = [
Base.read_memory(pointer, register, e.bits, false),
Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))
];
if (e.opd[0].postadd) {
ptr_reg = e.opd[0].register;
ops.push(Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8)));
}
return Base.composed(ops);
} else if (e.opd[0].postadd) {
ptr_reg = e.opd[0].register;
ops = [
Base.read_memory(pointer, register, e.bits, false),
Base.add(ptr_reg, ptr_reg, '' + (e.bits / 8))
];
return Base.composed(ops);
}
return Base.read_memory(pointer, register, e.bits, false);
},
movea: _move,
movem: _move_multiple,
moveq: function(instr, context) {
instr.setBadJump();
return Base.assign(instr.parsed.opd[1].register, instr.parsed.opd[0].register);
},
or: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.or);
},
ori: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.or);
},
pea: function(instr) {
instr.setBadJump();
var bits = instr.parsed.bits;
var pointer = Variable.pointer('a7 -= 4', bits, false);
var register = instr.string ? Variable.string(instr.string) : _as_pointer(instr.parsed, 0, false);
return Base.write_memory(pointer, register, bits, false);
},
rts: function(instr) {
instr.setBadJump();
return Base.return();
},
sf: function(instr, context) {
instr.setBadJump();
var e = instr.parsed;
var dst = _as_pointer(e, 0, false, true);
var op = Base.assign(dst, '0');
if (e.opd[1].postadd) {
return Base.composed([op, Base.add(e.opd[1].register, e.opd[1].register, '' + (e.bits / 8))]);
}
return op;
},
st: function(instr, context) {
instr.setBadJump();
var e = instr.parsed;
var dst = _as_pointer(e, 0, false, true);
var op = Base.assign(dst, '1');
if (e.opd[0].postadd) {
return Base.composed([op, Base.add(e.opd[0].register, e.opd[0].register, '' + (e.bits / 8))]);
}
return op;
},
sub: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.subtract);
},
subq: function(instr) {
instr.setBadJump();
return _common_math(instr.parsed, Base.subtract);
},
tst: function(instr, context) {
instr.setBadJump();
context.cond.a = _as_pointer(instr.parsed, 0, false);
context.cond.b = '0';
return Base.nop();
},
unlk: function(instr) {
instr.setBadJump();
var e = instr.parsed;
return Base.read_memory(e.opd[1].register || 'a7', e.opd[0].register, e.bits, false);
},
invalid: function(instr) {
instr.setBadJump();
return Base.nop();
}
},
parse: function(asm) {
const expr = /([a-zA-Z]+)(\.[bwl])?\s+([\w.:_-]+\([\w. *,[\]]+\)|-?\([\w. *,[\]]+\)\+?|[\w./:_-]+)(?:,\s+([\w.:_-]+\([\w. *,[\]]+\)|-?\([\w. *,[\]]+\)\+?|[\w./:_-]+))?/;
var token = asm.match(expr);
token.shift();
/*
* [
"move.l obj.__unctrl(d0.l * 4), -(a7)",
"move",
".l",
"obj.__unctrl(d0.l * 4)",
"-(a7)"
* ]
* token[0] = assembly
* token[1] = mnem
* token[2] = bits
* token[3] = opd0
* token[4] = opd1
*/
var mnem = token.shift();
var bits = token.shift();
var ret = {
mnem: mnem,
bits: _to_size(bits ? bits.substring(1) : 'l'),
opd: token.filter(function(x) {
return x ? true : false;
}).map(function(x) {
var d = {
presub: false,
postadd: false,
pointer: null,
register: null,
};
var isreg = x.indexOf('(') < 0;
var ptr = x.replace(/([\w.:_-][\w.:_-]+)\(/, '$1 + ').replace(/(-?\()|\)\+?/g, ' ').replace(/,\sinvalid\.[bwl]/, '');
var p = x.replace(/[(),]/g, ' ').replace(/\s+/g, ' ');
p = p.replace(/invalid\.[bwl]/, '');
p = p.trim().split(' ');
if (p[0] == '-') {
d.presub = true;
p.shift();
} else if (p[p.length - 1] == '+') {
d.postadd = true;
p.pop();
}
if (isreg) {
d.register = p.pop();
} else if (ptr.indexOf('-') > 0 || ptr.indexOf('+') > 0 || ptr.indexOf('*') > 0) {
d.pointer = ptr.replace(/(\d)\.[bwl]/, '$1').replace(/,/g, ' +').trim();
d.register = ptr.match(/[ad]\d+/)[0];
} else {
d.pointer = p.join(' + ');
d.register = p[0];
}
return d;
}),
};
return ret;
},
context: function() {
return {
cond: {
a: '?',
b: '?'
},
leave: false,
vars: []
};
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
});
-1864
View File
File diff suppressed because it is too large. Load diff
-588
View File
@@ -1,588 +0,0 @@
// SPDX-FileCopyrightText: 2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
var Base = require('libdec/core/base');
var Variable = require('libdec/core/variable');
var Long = require('libdec/long');
function load_bits(instr, bits, unsigned) {
instr.setBadJump();
var e = instr.parsed;
var arg = e.opd[1].replace(/\)/, '').split('(');
if (arg[0].indexOf('-sym.') == 0 && arg[1] == 'gp') {
return Base.assign(e.opd[0], arg[0].replace(/^-/, ''));
} else if (arg[1] == '0') {
//pointer, register, bits, is_signed
return Base.read_memory(arg[0], e.opd[0], bits, !unsigned);
} else if (arg[0] == '0') {
//pointer, register, bits, is_signed
return Base.read_memory(arg[1], e.opd[0], bits, !unsigned);
}
arg[0] = arg[0].length > 0 ? parseInt(arg[0]) : NaN;
if (!isNaN(arg[0])) {
if (arg[0] < 0) {
arg[0] = " - 0x" + Math.abs(arg[0]).toString(16);
} else {
arg[0] = " + 0x" + arg[0].toString(16);
}
return Base.read_memory(arg[1] + arg[0], e.opd[0], bits, !unsigned);
}
return Base.read_memory(arg[1], e.opd[0], bits, !unsigned);
}
function store_bits(instr, bits, unsigned) {
instr.setBadJump();
var e = instr.parsed;
var arg = e.opd[1].replace(/\)/, '').split('(');
if (arg[1] == '0') {
//pointer, register, bits, is_signed
return Base.write_memory(arg[0], e.opd[0], bits, !unsigned);
} else if (arg[0] == '0') {
//pointer, register, bits, is_signed
return Base.write_memory(arg[1], e.opd[0], bits, !unsigned);
}
arg[0] = arg[0].length > 0 ? parseInt(arg[0]) : NaN;
if (!isNaN(arg[0])) {
if (arg[0] < 0) {
arg[0] = " - 0x" + Math.abs(arg[0]).toString(16);
} else {
arg[0] = " + 0x" + arg[0].toString(16);
}
return Base.write_memory(arg[1] + arg[0], e.opd[0], bits, !unsigned);
}
return Base.write_memory(arg[1], e.opd[0], bits, !unsigned);
}
function _csr_assign_3arg(instr) {
instr.setBadJump();
var dst = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
return Base.assign(dst, src);
}
function _generic_assign(instr) {
instr.setBadJump();
var dst = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
return Base.assign(dst, src);
}
function _generic_add(instr) {
instr.setBadJump();
var dst = instr.parsed.opd[0];
var src0 = instr.parsed.opd[1];
var src1 = instr.parsed.opd[2];
return Base.add(dst, src0, src1);
}
function op_bits3(instr, op) {
instr.setBadJump();
var dst = instr.parsed.opd[0];
var src0 = instr.parsed.opd[1];
var src1 = instr.parsed.opd[2];
return op(dst, src0, src1);
}
function assign_call(instr, name) {
var dst = instr.parsed.opd[0];
var args = instr.parsed.opd.slice(1);
return Base.special(dst + ' = ' + name + '( ', args.join(', ') + ')');
}
function _compare(instr, context, instructions, cmp, zero) {
instr.conditional(instr.parsed.opd[0], zero ? "0" : instr.parsed.opd[1], cmp);
var arg = instr.parsed.opd[instr.parsed.opd.length - 1];
if (arg.indexOf('0x') == 0) {
instr.jump = Long.fromString(arg);
}
return Base.nop();
}
function _is_last_instruction(instr, instructions) {
return instructions.indexOf(instr) == (instructions.length - 1);
}
function _hex(value) {
return parseInt(value).toString(16);
}
function lui32(instr, start, instructions, context) {
var addr = null;
var check = [
function(e, r) {
return e.mnem == 'lui' && e.opd[0] == r;
},
function(e, r) {
if (e.mnem == 'nop') {
return true;
}
return (e.mnem == 'ori' && (e.opd[0] == r || e.opd[0].indexOf('a') == 0) && e.opd[1] == r) ||
(e.mnem == 'addi' && (e.opd[0] == r || e.opd[0].indexOf('a') == 0) && e.opd[1] == r) ||
(e.mnem == 'addiu' && (e.opd[0] == r || e.opd[0].indexOf('a') == 0) && e.opd[1] == r);
},
];
var address = [
function(e, addr) {
var imm32 = instr.parsed.opd[1] << 12;
return Long.fromNumber(imm32, true);
},
function(e, addr) {
var n = Long.fromString(_hex(e.opd[2]), e.mnem.indexOf('u') > 0, 16);
var op = e.mnem.replace(/[iu]/g, '');
return addr[op](n);
},
];
var step = 0;
var i;
for (i = start; i < instructions.length && step < check.length; ++i) {
var elem = instructions[i].parsed;
if (!check[step](elem, instr.parsed.opd[0])) {
break;
}
addr = address[step](elem, addr);
step++;
if (instr.parsed.opd[0] == instructions[i].parsed.opd[0]) {
instructions[i].valid = false;
} else {
instr.valid = true;
instr = instructions[i];
}
}
--i;
if (instr.parsed.opd[0] != 'gp') {
instr.string = Global.xrefs.find_string(addr);
instr.symbol = Global.xrefs.find_symbol(addr);
addr = instr.string ? Variable.string(instr.string) : (instr.symbol || ('0x' + addr.toString(16)).replace(/0x-/, '-0x'));
instr.valid = true;
} else {
addr = ('0x' + addr.toString(16)).replace(/0x-/, '-0x');
instr.valid = false;
}
instr.code = Base.assign(instr.parsed.opd[0], addr);
return i;
}
return {
instructions: {
auipc: function(instr) {
var dst = instr.parsed.opd[0];
var imm32 = parseInt(instr.parsed.opd[1]);
var src = instr.location.add(imm32);
return Base.assign(dst, '0x' + src.toString(16)) ;
},
lui: function(instr) {
var dst = instr.parsed.opd[0];
var imm20 = instr.parsed.opd[1] << 12;
return Base.assign(dst, '0x' + imm20.toString(16)) ;
},
lb: function(instr) {
return load_bits(instr, 8, false);
},
lh: function(instr) {
return load_bits(instr, 16, false);
},
lw: function(instr) {
return load_bits(instr, 32, false);
},
lwu: function(instr) {
return load_bits(instr, 32, true);
},
ld: function(instr) {
return load_bits(instr, 64, false);
},
lbu: function(instr) {
return load_bits(instr, 8, true);
},
lhu: function(instr) {
return load_bits(instr, 16, true);
},
'lr.w': function(instr) {
return load_bits(instr, 32, false);
},
'lr.d': function(instr) {
return load_bits(instr, 64, false);
},
sb: function(instr) {
return store_bits(instr, 8, false);
},
sh: function(instr) {
return store_bits(instr, 16, false);
},
sw: function(instr) {
return store_bits(instr, 32, false);
},
sd: function(instr) {
return store_bits(instr, 64, false);
},
'sc.w': function(instr) {
return store_bits(instr, 32, false);
},
'sc.d': function(instr) {
return store_bits(instr, 64, false);
},
'sext.w': function(instr) {
return Base.extend(instr.parsed.opd[0], instr.parsed.opd[1], 32);
},
add: _generic_add,
addi: _generic_add,
addw: _generic_add,
addiw: _generic_add,
and: function(instr) {
return op_bits3(instr, Base.and);
},
andi: function(instr) {
return op_bits3(instr, Base.and);
},
sub: function(instr) {
return op_bits3(instr, Base.subtract);
},
subw: function(instr) {
return op_bits3(instr, Base.subtract);
},
mul: function(instr) {
return op_bits3(instr, Base.multiply);
},
mulh: function(instr) {
return op_bits3(instr, Base.multiply);
},
mulw: function(instr) {
return op_bits3(instr, Base.multiply);
},
srli: function(instr) {
return op_bits3(instr, Base.shift_right);
},
srai: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sll: function(instr) {
return op_bits3(instr, Base.shift_left);
},
slli: function(instr) {
return op_bits3(instr, Base.shift_left);
},
srlw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
srliw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sraw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sraiw: function(instr) {
return op_bits3(instr, Base.shift_right);
},
sllw: function(instr) {
return op_bits3(instr, Base.shift_left);
},
slliw: function(instr) {
return op_bits3(instr, Base.shift_left);
},
div: function(instr) {
return op_bits3(instr, Base.divide);
},
divu: function(instr) {
return op_bits3(instr, Base.divide);
},
rem: function(instr) {
return op_bits3(instr, Base.module);
},
remu: function(instr) {
return op_bits3(instr, Base.module);
},
divw: function(instr) {
return op_bits3(instr, Base.divide);
},
divuw: function(instr) {
return op_bits3(instr, Base.divide);
},
remw: function(instr) {
return op_bits3(instr, Base.module);
},
remuw: function(instr) {
return op_bits3(instr, Base.module);
},
or: function(instr) {
return op_bits3(instr, Base.or);
},
ori: function(instr) {
return op_bits3(instr, Base.or);
},
xor: function(instr) {
return op_bits3(instr, Base.xor);
},
xori: function(instr) {
return op_bits3(instr, Base.xor);
},
'slt': function(instr) {
var e = instr.parsed;
return Base.conditional_assign(e.opd[0], e.opd[1], e.opd[2], 'LT', '1', '0');
},
'slti': function(instr) {
var e = instr.parsed;
return Base.conditional_assign(e.opd[0], e.opd[1], e.opd[2], 'LT', '1', '0');
},
'sltiu': function(instr) {
var e = instr.parsed;
var arg0 = Variable.local(e.opd[1], 32);
var arg1 = Variable.local(e.opd[2], 32);
return Base.conditional_assign(e.opd[0], arg0, arg1, 'LT', '1', '0');
},
'sltu': function(instr) {
var e = instr.parsed;
if (e.opd[2] == 'zero') {
e.opd[2] = '0';
}
var arg0 = Variable.local(e.opd[1], 32);
var arg1 = Variable.local(e.opd[2], 32);
return Base.conditional_assign(e.opd[0], arg0, arg1, 'LT', '1', '0');
},
'amoadd.w': _generic_add,
'amoor.w': function(instr) {
return op_bits3(instr, Base.or);
},
'amoxor.w': function(instr) {
return op_bits3(instr, Base.xor);
},
'amoand.w': function(instr) {
return op_bits3(instr, Base.and);
},
'amomin.w': function(instr) {
return assign_call(instr, 'min');
},
'amominu.w': function(instr) {
return assign_call(instr, 'min');
},
'amomax.w': function(instr) {
return assign_call(instr, 'max');
},
'amomaxu.w': function(instr) {
return assign_call(instr, 'max');
},
'amoadd.d': _generic_add,
'amoor.d': function(instr) {
return op_bits3(instr, Base.or);
},
'amoxor.d': function(instr) {
return op_bits3(instr, Base.xor);
},
'amoand.d': function(instr) {
return op_bits3(instr, Base.and);
},
'amomin.d': function(instr) {
return assign_call(instr, 'min');
},
'amominu.d': function(instr) {
return assign_call(instr, 'min');
},
'amomax.d': function(instr) {
return assign_call(instr, 'max');
},
'amomaxu.d': function(instr) {
return assign_call(instr, 'max');
},
mv: _generic_assign,
li: _generic_assign,
csrr: _generic_assign,
csrw: _generic_assign,
csrc: _generic_assign,
csrs: _generic_assign,
csrri: _generic_assign,
csrwi: _generic_assign,
csrci: _generic_assign,
csrsi: _generic_assign,
csrrwi: _csr_assign_3arg,
csrrci: _csr_assign_3arg,
csrrsi: _csr_assign_3arg,
beqz: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'EQ', true);
},
bnez: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'NE', true);
},
bltz: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LT', true);
},
blez: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LE', true);
},
bgtz: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GT', true);
},
bgez: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GE', true);
},
beq: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'EQ', false);
},
bne: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'NE', false);
},
blt: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LT', false);
},
ble: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LE', false);
},
bgt: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GT', false);
},
bge: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GE', false);
},
bltu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LT', false);
},
bleu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'LE', false);
},
bgtu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GT', false);
},
bgeu: function(instr, context, instructions) {
return _compare(instr, context, instructions, 'GE', false);
},
jal: function(instr, context, instructions) {
var fcn_name = instr.parsed.opd[1].replace(/\./g, '_');
if (fcn_name.indexOf('0x') == 0) {
fcn_name = fcn_name.replace(/0x/, 'fcn_');
}
var args = [];
var regs = ['a7', 'a6', 'a5', 'a4', 'a3', 'a2', 'a1', 'a0'];
var found = 0, i;
for (i = instructions.indexOf(instr) - 1; i >= 0; i--) {
if (instructions[i].parsed.mnem.startsWith('b') ||
instructions[i].parsed.mnem.startsWith('j')) {
break;
}
var reg = instructions[i].parsed.opd[0];
if (regs.indexOf(reg) >= 0) {
found = parseInt(reg.substr(1, 3)) + 1;
break;
}
}
for (i = 0; i < found; i++) {
args.push('a' + i);
}
return Base.call(fcn_name, args);
},
jalr: function(instr) {
var is_return = false;
var arg = instr.parsed.opd[0];
if (arg.indexOf('(') > 0) {
arg = arg.replace(/\(|\)/g, ' ').trim().split(' ');
if (arg[1] == 'ra') {
is_return = true;
}
arg = arg[1] + ' + ' + arg[0];
arg = arg.replace(/\+ -/, '-');
}
if (is_return || arg == 'ra') {
if (is_return) {
instr.comments.push('return address: ' + arg);
}
return Base.return(instr.parsed.opd[1]);
}
return Base.call(arg, [], true);
},
j: function(instr, context, instructions) {
var arg = instr.parsed.opd[0];
if (arg.indexOf('0x') == 0) {
instr.jump = Long.fromString(arg);
} else if (_is_last_instruction(instr, instructions)) {
return Base.call(arg, []);
}
return Base.nop();
},
ret: function(instr) {
return Base.return();
},
uret: function(instr) {
return Base.return();
},
sret: function(instr) {
return Base.return();
},
mret: function(instr) {
return Base.return();
},
fence: function() {
return Base.macro('memory_fence()', '#define memory_fence() __asm(fence)');
},
'fence.i': function() {
return Base.macro('memory_fence_i()', '#define memory_fence_i() __asm(fence.i)');
},
'sfence.vma': function() {
return Base.macro('memory_sfence_vma()', '#define memory_sfence_vma() __asm(sfence.vma)');
},
ebreak: function() {
return Base.macro('environment_break()', '#define environment_break() __asm(ebreak)');
},
ecall: function() {
return Base.macro('environment_call()', '#define environment_call() __asm(ecall)');
},
wfi: function() {
return Base.macro('wait_for_interrupt()', '#define wait_for_interrupt() __asm(wfi)');
},
nop: function(instr) {
return Base.nop();
},
invalid: function() {
return Base.nop();
}
},
parse: function(asm) {
asm = asm.replace(/,/g, ' ').replace(/\s+/g, ' ').trim().split(' ').map(function(x) {
if (x == 'zero') {
return '0';
}
return x;
});
var mnem = asm.shift();
if (mnem.indexOf('amo') == 0) {
// atomic ops.
asm = asm.map(function(x) {
return x.replace(/\(|\)/g, '');
});
}
return {
mnem: mnem,
opd: asm
};
},
context: function() {
return {
cond: {
a: null,
b: null
}
};
},
preanalisys: function(instructions) {
},
postanalisys: function(instructions, context) {
/* simplifies any load address 32/64 bit */
for (var i = 0; i < instructions.length; i++) {
if (instructions[i].parsed.mnem == 'lui') {
i = lui32(instructions[i], i, instructions);
}
}
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
});
-547
View File
@@ -1,547 +0,0 @@
// SPDX-FileCopyrightText: 2019-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
// https://www.rockbox.org/wiki/pub/Main/DataSheets/sh1_2p.pdf
// http://www.shared-ptr.com/sh_insns.html
const Instruction = require('libdec/core/instruction');
const Base = require('libdec/core/base');
const Variable = require('libdec/core/variable');
//const Extra = require('libdec/core/extra');
const _s = 's';
const _carry = 'c';
const _mac = 'mac';
const _size_map = {
"b": 8,
"w": 16,
"l": 32
};
const _compare_map = {
'eq': 'EQ',
'hi': 'GT',
'hs': 'GE',
'ge': 'GE',
'gt': 'GT',
'pl': 'GT',
'pz': 'GE',
'str': 'str',
};
const _reverse_map = {
'EQ': 'NE',
'GT': 'LE',
'GE': 'LT',
};
const _branch_list = [
'bra',
'braf',
'bsr',
'bsrf',
'jmp',
'jsr',
'rte',
'rts'
];
function _set_conditional(instr, context, cmp, invert) {
if (invert) {
cmp = _reverse_map[cmp];
}
instr.conditional(context.cond.a, context.cond.b, cmp);
return Base.nop();
}
function _require_composed(instr, idx) {
var e = instr.parsed;
return e.opd[idx].increment || e.opd[idx].decrement;
}
function _handle_pointer(instr, idx, ops) {
var e = instr.parsed;
var size = e.size || 32;
if (e.opd[idx].increment) {
ops.push(Base.increase(e.opd[idx].token, size / 8));
} else if (e.opd[idx].decrement) {
ops.unshift(Base.decrease(e.opd[idx].token, size / 8));
}
}
function _arg(instr, idx) {
var e = instr.parsed;
if (e.opd[idx].pointer) {
// a great way to fix PC + N
if (e.opd[idx].token.startsWith('pc +')) {
var n = parseInt(e.opd[idx].token.substr('pc +'.length));
var p = instr.location.add(n);
e.opd[idx].token = '0x' + p.toString(16);
}
return Variable.pointer(e.opd[idx].toString(), e.size || 32, true);
}
return e.opd[idx].toString();
}
function _op_move(instr) {
var ops = [];
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
if (instr.parsed.size) {
ops.push(Base.cast(dst, src, 'int' + instr.parsed.size + '_t'));
} else {
ops.push(Base.assign(dst, src));
}
if (_require_composed(instr, 0) || _require_composed(instr, 1)) {
if (_require_composed(instr, 0)) {
_handle_pointer(instr, 0, ops);
} else {
_handle_pointer(instr, 1, ops);
}
return Base.composed(ops);
}
return ops[0];
}
return {
instructions: {
mov: _op_move,
mova: _op_move,
movt: function(instr, context, instructions) {
instr.parsed.opd[0].token = _carry;
return _op_move(instr);
},
swap: function(instr, context, instructions) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.swap(dst, src, 32);
},
/*
xtrct: function(instr, context, instructions) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.?????(dst, src);
},
*/
add: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.add(dst, dst, src);
},
addc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.add(dst, dst, src + ' + ' + _carry);
},
addv: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
instr.comments.push('if overflows, then ' + _carry + ' = 1.');
return Base.add(dst, dst, src + ' + ' + _carry);
},
cmp: function(instr, context) {
var a = _arg(instr, 0);
var b = _arg(instr, 1);
if (instr.parsed.cmp != 'str') {
context.cond.a = a;
context.cond.b = b;
context.cond.cmp = instr.parsed.cmp;
} else {
context.cond.a = (a === b) ? a : '(' + a + ' & ' + b + ')';
context.cond.b = '0';
context.cond.cmp = 'EQ';
}
},
tst: function(instr, context) {
var a = _arg(instr, 0);
var b = _arg(instr, 1);
context.cond.a = (a === b) ? a : '(' + a + ' & ' + b + ')';
context.cond.b = '0';
context.cond.cmp = 'EQ';
},
div1: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.divide(dst, dst, src);
},
dmuls: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(dst, dst, src);
},
dt: function(instr) {
var dst = _arg(instr, 1);
return Base.decrease(dst, dst, 1);
},
exts: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'int' + instr.parsed.size + '_t');
},
extu: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'uint' + instr.parsed.size + '_t');
},
mul: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(_mac, dst, src);
},
muls: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(_mac, dst, src);
},
mulu: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(_mac, dst, src);
},
neg: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.negate(dst, src);
},
negc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.composed([
Base.negate(dst, src),
Base.subtract(dst, dst, _carry),
]);
},
sub: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.subtract(dst, dst, src);
},
subc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.composed([
Base.subtract(dst, dst, src),
Base.subtract(dst, dst, _carry),
]);
},
subv: function(instr) {
instr.comments.push('if underflows, then ' + _carry + ' = 1.');
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.subtract(dst, dst, src);
},
and: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.and(dst, dst, src);
},
not: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.not(dst, src);
},
or: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.or(dst, dst, src);
},
xor: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.xor(dst, dst, src);
},
rotl: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_left(src, src, 1, 32);
},
rotr: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_right(src, src, 1, 32);
},
rotcl: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_left(src, src, 1, 32);
},
rotcr: function(instr) {
var src = _arg(instr, 1);
return Base.rotate_right(src, src, 1, 32);
},
shal: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 1);
},
shar: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 1);
},
shll: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 1);
},
shlr: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 1);
},
shll2: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 2);
},
shlr2: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 2);
},
shll8: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 8);
},
shlr8: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 8);
},
shll16: function(instr) {
var src = _arg(instr, 1);
return Base.shift_left(src, src, 16);
},
shlr16: function(instr) {
var src = _arg(instr, 1);
return Base.shift_right(src, src, 16);
},
ldc: _op_move,
lds: _op_move,
stc: _op_move,
sts: _op_move,
clrt: function(instr) {
return Base.assign(_carry, '0');
},
clrs: function(instr) {
return Base.assign(_s, '0');
},
sett: function(instr) {
return Base.assign(_carry, '1');
},
sets: function(instr) {
return Base.assign(_s, '1');
},
fmov: _op_move,
flds: _op_move,
fsts: _op_move,
fldi0: function(instr) {
var src = _arg(instr, 1);
return Base.assign(src, '0.0');
},
fldi1: function(instr) {
var src = _arg(instr, 1);
return Base.assign(src, '1.0');
},
fabs: function(instr) {
var src = _arg(instr, 1);
return Base.and(src, src, '0x7FFFFFFF');
},
fneg: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.negate(dst, src);
},
fadd: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.add(dst, dst, src);
},
fsub: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.subtract(dst, dst, src);
},
fmul: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.multiply(dst, dst, src);
},
fdiv: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.divide(dst, dst, src);
},
fsqrt: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.assign(dst, Base.call('sqrt', [src]));
},
fcmp: function(instr, context) {
var a = _arg(instr, 0);
var b = _arg(instr, 1);
context.cond.a = a;
context.cond.b = b;
context.cond.cmp = instr.parsed.cmp;
},
float: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'float');
},
ftrc: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.cast(dst, src, 'int32_t');
},
fsrra: function(instr) {
var dst = _arg(instr, 0);
var src = _arg(instr, 1);
return Base.special(dst + ' = 1.0 / sqrt (' + src + ')');
},
fsca: function(instr) {
var dst1 = _arg(instr, 0);
var dst2 = 'fr' + (parseInt(dst1.substr(2)) + 1).toString(16);
var src = _arg(instr, 1);
return Base.composed([
Base.assign(dst1, Base.call('sin', [src])),
Base.assign(dst2, Base.call('cos', [src]))
]);
},
bt: function(instr, context, instructions) {
return _set_conditional(instr, context, 'EQ');
},
bf: function(instr, context, instructions) {
return _set_conditional(instr, context, 'NE');
},
jsr: function(instr, context, instructions) {
var e = instr.parsed.opd;
return Base.call(Variable.functionPointer(e[1].token), []);
},
bra: function(instr) {
var callname = _arg(instr, 1);
if (callname.startsWith('0x')) {
callname = Variable.functionPointer(callname);
}
return Base.call(callname, []);
},
braf: function(instr) {
var src = _arg(instr, 1);
return Base.call(Variable.functionPointer(src), []);
},
rte: function() {
return Base.return();
},
rts: function() {
return Base.return();
},
nop: function() {
return Base.nop();
},
invalid: function(instr, context, instructions) {
return Base.nop();
}
},
parse: function(assembly) {
assembly = assembly.trim().toLowerCase();
assembly = assembly.replace(/,/g, ' ');
assembly = assembly.replace(/\s+/g, ' ');
/*
Regex explaination:
^
(\w+)
\.?
([wlb])? // word/long/byte
([sn])? // delayed branch
\/?
(hi|eq|hs|pl|pz|str)? // compare flags
? // space might not exists (aka no 1st and 2nd param)
(
(
(@)? // Indirect or Direct access
(
(\(\w+\s\w+\)) A + B value
|
(-)? Pre-decrement
([\w._]+) register
(\+)? Post-increment
)
)
)?
? // space might not exists (aka no 2nd param)
(
(
(@)? // Indirect or Direct access
(
(\(\w+\s\w+\)) A + B value
|
(-)? Pre-decrement
([\w._]+) register
(\+)? Post-increment
)
)
)?
$
*/
var tokens = assembly.match(/^(\w+)\.?([wlb])?([sn])?\/?(hi|eq|hs|pl|pz|str)? ?(((@)?((\(\w+\s\w+\))|(-)?([\w._]+)(\+)?)))? ?(((@)?((\(\w+\s\w+\))|(-)?([\w._]+)(\+)?)))?$/);
var mnem = tokens[1];
var size = _size_map[tokens[2]];
var delayed = tokens[3] == 's';
var cmp = _compare_map[tokens[4]];
var opd = [{
pointer: tokens[7] == '@',
decrement: tokens[10] == '-',
increment: tokens[12] == '+',
token: tokens[11] || (tokens[9] ? tokens[9].replace(/\((\w+)\s(\w+)\)/g, '$2 + $1') : null),
toString: function() {
return this.token || '(null)';
}
}, {
pointer: tokens[15] == '@',
decrement: tokens[18] == '-',
increment: tokens[20] == '+',
token: tokens[19] || (tokens[17] ? tokens[17].replace(/\((\w+)\s(\w+)\)/g, '$2 + $1') : null),
toString: function() {
return this.token || '(null)';
}
}];
return {
mnem: mnem,
delayed: delayed,
cmp: cmp,
size: size,
opd: opd.reverse()
};
},
context: function() {
return {
cond: {
cmp: null,
a: '?',
b: '?'
}
};
},
preanalisys: function(instructions, context) {
/* delayed branch fix */
for (var i = 0; i < (instructions.length - 1); i++) {
var op = instructions[i].parsed.mnem;
if (_branch_list.indexOf(op) >= 0 && instructions[i + 1].parsed.mnem != 'nop') {
Instruction.swap(instructions, i, i + 1);
++i;
} else if (instructions[i].parsed.delayed && instructions[i + 1].parsed.mnem != 'nop') {
Instruction.swap(instructions, i, i + 1);
++i;
}
}
},
postanalisys: function(instructions, context) {},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
});
-398
View File
@@ -1,398 +0,0 @@
// SPDX-FileCopyrightText: 2018-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
var Instruction = require('libdec/core/instruction');
var Base = require('libdec/core/base');
var Variable = require('libdec/core/variable');
var Long = require('libdec/long');
var _call_fix_name = function(name) {
if (typeof name != 'string') {
return name;
}
if (name.indexOf('fcn.') == 0 || name.indexOf('func.') == 0) {
return name.replace(/[.:]/g, '_').replace(/__+/g, '_');
}
return name.replace(/\[reloc\.|\]/g, '').replace(/[.:]/g, '_').replace(/__+/g, '_').replace(/_[0-9a-f]+$/, '').replace(/^_+/, '');
};
var _load = function(instr, context, instruction, signed, bits) {
var e = instr.parsed;
if (e.opd[0].indexOf('+') > 0) {
var arg = e.opd[0].split('+');
var ops = [];
var value = Variable.uniqueName('local');
if (arg[1].indexOf('-') < 0) {
ops.push(Base.add(value, arg[0], arg[1]));
} else {
ops.push(Base.subtract(value, arg[0], arg[1].replace(/-/, '')));
}
ops.push(Base.read_memory(value, e.opd[1], bits, signed));
return Base.composed(ops);
}
//pointer, register, bits, is_signed
return Base.read_memory(e.opd[0], e.opd[1], bits, signed);
};
var _store = function(instr, context, instruction, signed, bits) {
var e = instr.parsed;
if (e.opd[1].indexOf('+') > 0) {
var arg = e.opd[1].split('+');
var ops = [];
var value = Variable.uniqueName('local');
if (arg[1].indexOf('-') < 0) {
ops.push(Base.add(value, arg[0], arg[1]));
} else {
ops.push(Base.subtract(value, arg[0], arg[1].replace(/-/, '')));
}
ops.push(Base.write_memory(value, e.opd[0], bits, signed));
return Base.composed(ops);
}
//pointer, register, bits, is_signed
return Base.write_memory(e.opd[1], e.opd[0], bits, signed);
};
var _conditional = function(instr, context, type) {
instr.conditional(context.cond.a, context.cond.b, type);
return Base.nop();
};
var _compare = function(instr, context, instructions) {
context.cond.a = instr.parsed.opd[0];
context.cond.b = instr.parsed.opd[1];
};
var sethi32 = function(instr, start, instructions) {
var addr = null;
var check = [
function(e, r) {
return e.mnem == 'sethi' && e.opd[1] == r;
},
function(e, r) {
if (e.mnem == 'nop') {
return true;
}
return (e.mnem == 'or' && e.opd[0] == r && e.opd[2] == r) || (e.mnem == 'add' && e.opd[0] == r && e.opd[2] == r);
}
];
var address = [
function(e, addr) {
var v = Long.fromString(parseInt(e.opd[0]).toString(16), false, 16);
return v.shl(10);
},
function(e, addr) {
var n = Long.fromString(parseInt(e.opd[1]).toString(16), false, 16);
return addr[e.mnem](n);
},
];
var step = 0;
var i;
for (i = start; i < instructions.length && step < check.length; ++i) {
var elem = instructions[i].parsed;
if (!check[step](elem, instr.parsed.opd[1])) {
break;
}
addr = address[step](elem, addr);
step++;
instructions[i].code = Base.nop();
}
if (addr) {
--i;
addr = '0x' + addr.toString(16);
instr.code = Base.assign(instr.parsed.opd[1], addr.replace(/0x-/, '-0x'));
}
return i;
};
var _branch_list = [
'ba', 'bn', 'be', 'bne', 'bl', 'ble', 'bge', 'bg',
'blu', 'bleu', 'bgeu', 'bgu', 'bpos', 'bneg',
'bcs', 'bcc', 'bvs', 'bvc', 'call', 'jmp', 'jmpl',
'ret', 'retl', 'rett'
];
return {
instructions: {
add: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
addcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
addx: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
addxcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
and: function(instr, context, instructions) {
return Base.and(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
andcc: function(instr, context, instructions) {
_compare(instr, context);
return Base.and(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
andn: function(instr, context, instructions) {
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.and(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
andncc: function(instr, context, instructions) {
_compare(instr, context);
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.and(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
ba: function(instr, context, instructions) {
return Base.nop();
},
bn: function(instr, context, instructions) {
return Base.nop();
},
be: function(instr, context, instructions) {
return _conditional(instr, context, 'EQ');
},
bne: function(instr, context, instructions) {
return _conditional(instr, context, 'NE');
},
bg: function(instr, context, instructions) {
return _conditional(instr, context, 'GT');
},
bge: function(instr, context, instructions) {
return _conditional(instr, context, 'GE');
},
bl: function(instr, context, instructions) {
return _conditional(instr, context, 'LT');
},
ble: function(instr, context, instructions) {
return _conditional(instr, context, 'LE');
},
blu: function(instr, context, instructions) {
return _conditional(instr, context, 'LT');
},
bleu: function(instr, context, instructions) {
return _conditional(instr, context, 'LE');
},
bgeu: function(instr, context, instructions) {
return _conditional(instr, context, 'GE');
},
bgu: function(instr, context, instructions) {
return _conditional(instr, context, 'GT');
},
bpos: function(instr, context, instructions) {
return _conditional(instr, context, 'GE');
},
bneg: function(instr, context, instructions) {
return _conditional(instr, context, 'LT');
},
call: function(instr, context, instructions) {
return Base.call(_call_fix_name(instr.parsed.opd[0]), []);
},
cmp: _compare,
ldub: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 8);
},
ldsb: function(instr, context, instructions) {
return _load(instr, context, instructions, true, 8);
},
lduh: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 16);
},
ldsh: function(instr, context, instructions) {
return _load(instr, context, instructions, true, 16);
},
ld: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 32);
},
ldd: function(instr, context, instructions) {
return _load(instr, context, instructions, false, 64);
},
mov: function(instr, context, instructions) {
return Base.assign(instr.parsed.opd[1], instr.parsed.opd[0]);
},
nop: function(instr) {
return Base.nop();
},
or: function(instr, context, instructions) {
return Base.or(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
orcc: function(instr, context, instructions) {
_compare(instr, context);
return Base.or(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
orn: function(instr, context, instructions) {
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.or(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
orncc: function(instr, context, instructions) {
_compare(instr, context);
var ops = [];
var value = Variable.uniqueName('local');
ops.push(Base.not(value, instr.parsed.opd[1]));
ops.push(Base.or(instr.parsed.opd[2], instr.parsed.opd[0], value));
return Base.composed(ops);
},
ret: function(instr, context, instructions) {
return Base.return();
},
retl: function(instr, context, instructions) {
return Base.return();
},
rett: function(instr, context, instructions) {
return Base.return();
},
restore: function(instr, context, instructions) {
return Base.nop();
},
save: function(instr, context, instructions) {
return Base.nop();
},
sethi: function(instr, context, instructions) {
var v = Long.fromString(parseInt(instr.parsed.opd[0]).toString(16), true, 16);
return Base.assign(instr.parsed.opd[1], '0x' + v.shl(10).toString(16));
},
sll: function(instr, context, instructions) {
return Base.shift_left(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
srl: function(instr, context, instructions) {
return Base.shift_right(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
sra: function(instr, context, instructions) {
return Base.shift_right(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
stb: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 8);
},
sth: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 16);
},
st: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 32);
},
std: function(instr, context, instructions) {
return _store(instr, context, instructions, false, 64);
},
sub: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
subcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
subx: function(instr, context, instructions) {
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
subxcc: function(instr, context, instructions) {
_compare(instr, context);
if (instr.parsed.opd[1].indexOf('-') >= 0) {
return Base.add(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1].replace(/-/, ''));
}
return Base.subtract(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
xor: function(instr, context, instructions) {
return Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
xorcc: function(instr, context, instructions) {
_compare(instr, context);
return Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]);
},
xnor: function(instr, context, instructions) {
var ops = [];
ops.push(Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.not(instr.parsed.opd[2], instr.parsed.opd[2]));
return Base.composed(ops);
},
xnorcc: function(instr, context, instructions) {
_compare(instr, context);
var ops = [];
ops.push(Base.xor(instr.parsed.opd[2], instr.parsed.opd[0], instr.parsed.opd[1]));
ops.push(Base.not(instr.parsed.opd[2], instr.parsed.opd[2]));
return Base.composed(ops);
},
unimp: function() {
return Base.nop();
},
invalid: function() {
return Base.nop();
}
},
parse: function(assembly) {
var tokens = assembly.replace(/,/g, ' ').replace(/\[|\]/g, '').replace(/\s+/g, ' ').trim().split(' ');
return {
mnem: tokens.shift(),
opd: tokens
};
},
context: function() {
return {
cond: {
a: null,
b: null
}
};
},
preanalisys: function(instructions) {
/* delayed branch fix */
for (var i = 0; i < (instructions.length - 1); i++) {
var op = instructions[i].parsed.mnem;
var n = instructions[i + 1].parsed.mnem;
if (_branch_list.indexOf(op) >= 0 && n != 'nop' && _branch_list.indexOf(n) < 0) {
Instruction.swap(instructions, i, i + 1);
++i;
}
}
},
postanalisys: function(instructions, context) {
/* simplifies any load address 32/64 bit */
for (var i = 0; i < instructions.length; i++) {
if (instructions[i].parsed.mnem == 'sethi') {
i = sethi32(instructions[i], i, instructions);
}
}
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
});
-519
View File
@@ -1,519 +0,0 @@
// SPDX-FileCopyrightText: 2018-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
var Base = require('libdec/core/base');
var Variable = require('libdec/core/variable');
var _common_math = function(e, op, reversed) {
if (e.opd[1] == '0') {
return Base.nop();
}
if (reversed) {
return op(e.opd[1], e.opd[0], e.opd[1]);
}
return op(e.opd[1], e.opd[1], e.opd[0]);
};
var _compare = function(instr, context) {
context.cond.a = instr.parsed.opd[1];
context.cond.b = instr.parsed.opd[0];
return Base.nop();
};
var _conditional = function(instr, context, type, zero) {
instr.conditional(context.cond.a, context.cond.b, type);
return Base.nop();
};
var load_bits = function(register, pointer, bits, signed) {
//pointer, register, bits, is_signed
return Base.read_memory(pointer, register, bits, signed);
};
var store_bits = function(register, pointer, bits, signed) {
//pointer, register, bits, is_signed
return Base.write_memory(pointer, register, bits, signed);
};
var _setf_v850_cond = {
'lt': {
cond: 'LT',
arg1: null,
},
'le': {
cond: 'LE',
arg1: null,
},
'ge': {
cond: 'GE',
arg1: null,
},
'gt': {
cond: 'GT',
arg1: null,
},
'nh': {
cond: 'LE',
arg1: null,
},
'h': {
cond: 'GT',
arg1: null,
},
'nz': {
cond: 'NE',
arg1: '0',
},
'z': {
cond: 'EQ',
arg1: '0',
}
};
return {
instructions: {
add: function(instr) {
return _common_math(instr.parsed, Base.add);
},
and: function(instr) {
return _common_math(instr.parsed, Base.and);
},
b: function() {
return Base.nop();
},
bne: function(instr, context) {
return _conditional(instr, context, 'EQ');
},
beq: function(instr, context) {
return _conditional(instr, context, 'NE');
},
bgt: function(instr, context) {
return _conditional(instr, context, 'LE');
},
bnh: function(instr, context) {
//branch not higher = LE
return _conditional(instr, context, 'GT');
},
bh: function(instr, context) {
//branch higher = GT
return _conditional(instr, context, 'LE');
},
bge: function(instr, context) {
return _conditional(instr, context, 'LT');
},
blt: function(instr, context) {
return _conditional(instr, context, 'GE');
},
ble: function(instr, context) {
return _conditional(instr, context, 'GT');
},
bz: function(instr, context) {
return _conditional(instr, context, 'NE');
},
bnz: function(instr, context) {
return _conditional(instr, context, 'EQ');
},
cmp: _compare,
jarl: function(instr, context, instructions) {
if (instr.parsed.opd[1] == '0') {
instr.comments.push('link pointer is lost. (used r0)');
} else {
instr.comments.push(instr.parsed.opd[1] + ' = PC + 4;');
}
var arg = instr.parsed.opd[0];
if (instr.parsed.opd[0].indexOf('0x') == 0) {
arg = Variable.functionPointer(arg);
}
return Base.call(arg, []);
},
jmp: function(instr, context, instructions) {
if ((instructions.length - 1) == instructions.indexOf(instr)) {
//name, args, is_pointer, returns, bits
return Base.call(instr.parsed.opd[0], [], true, 'return');
}
return Base.nop();
},
jr: function() {
return Base.nop();
},
'ld.b': function(instr) {
// ld.X 0x6c36[r4], r14
// ["ld.X","0x6c36","r4","r14"]
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, true);
}
return load_bits(dst, src + ' + ' + addr, 8, true);
},
'ld.bu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, false);
}
return load_bits(dst, src + ' + ' + addr, 8, false);
},
'ld.h': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, true);
}
return load_bits(dst, src + ' + ' + addr, 16, true);
},
'ld.hu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, false);
}
return load_bits(dst, src + ' + ' + addr, 16, false);
},
'ld.w': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 32, false);
}
return load_bits(dst, src + ' + ' + addr, 32, false);
},
mov: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.assign(instr.parsed.opd[1], instr.parsed.opd[0]);
},
movea: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
if (instr.parsed.opd[1] == '0') {
return Base.assign(instr.parsed.opd[2], instr.parsed.opd[0]);
}
if (instr.parsed.opd[0] == '0') {
return Base.assign(instr.parsed.opd[2], instr.parsed.opd[1]);
}
return Base.add(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
movhi: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
var a = instr.parsed.opd[0];
if (a.indexOf('0x') != 0) {
a = '0x' + parseInt(a).toString(16);
}
return Base.assign(instr.parsed.opd[1], a + '0000');
},
mul: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
//value, bits, is_signed, is_pointer, is_memory
var n = Variable.local(instr.parsed.opd[0], 32, true);
return Base.multiply(instr.parsed.opd[2], instr.parsed.opd[1], n);
},
mulh: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.multiply(instr.parsed.opd[1], instr.parsed.opd[1], instr.parsed.opd[0]);
},
mulhi: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
return Base.multiply(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
not: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.not(instr.parsed.opd[1], instr.parsed.opd[0]);
},
nop: function(instr) {
return Base.nop();
},
or: function(instr) {
return _common_math(instr.parsed, Base.or);
},
ori: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
return Base.or(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
satadd: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.add);
},
satsub: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.subtract, false);
},
satsubi: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.subtract, true);
},
satsubr: function(instr) {
// add with previous carry
return _common_math(instr.parsed, Base.subtract, true);
},
shl: function(instr) {
return _common_math(instr.parsed, Base.shift_left);
},
shr: function(instr) {
//logically shift right
return _common_math(instr.parsed, Base.shift_right);
},
setf: function(instr, context) {
var e = instr.parsed;
if (e.opd[1] == '0') {
return Base.nop();
}
if (e.opd[0] == 'v' || e.opd[0] == 'nv') {
var m = new Variable.macro((e.opd[0] == 'nv' ? '!' : '') + 'IS_OVERFLOW(' + context.cond.a + ', ' + context.cond.b + ')');
var op = Base.conditional_assign(e.opd[1], m, null, 'CUST', '1', '0');
Global.context.addMarcro('#define IS_OVERFLOW(a,b) (((a<0)&&(b<0)&&(a+b>0))||((a>0)&&(b>0)&&(a+b<0)))');
return op;
}
var o = _setf_v850_cond[e.opd[0]];
if (!o) {
instr.comments.push('unhandled use-case. please report it.');
instr.comments.push(instr.assembly);
return Base.nop();
}
return Base.conditional_assign(e.opd[1], context.cond.a, o.arg1 || context.cond.b, o.cond, '1', '0');
},
'sld.b': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, true);
}
return load_bits(dst, src + ' + ' + addr, 8, true);
},
'sld.bu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 8, false);
}
return load_bits(dst, src + ' + ' + addr, 8, false);
},
'sld.h': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, true);
}
return load_bits(dst, src + ' + ' + addr, 16, true);
},
'sld.hu': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 16, false);
}
return load_bits(dst, src + ' + ' + addr, 16, false);
},
'sld.w': function(instr) {
var addr = instr.parsed.opd[0];
var src = instr.parsed.opd[1];
var dst = instr.parsed.opd[2];
if (src == '0') {
return load_bits(dst, addr, 32, false);
}
return load_bits(dst, src + ' + ' + addr, 32, false);
},
'sst.b': function(instr) {
// st.X , r14, 0x6c36[r4]
// ["st.X","r14","0x6c36","r4"]
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, true);
}
return store_bits(dst, src + ' + ' + addr, 8, true);
},
'sst.bu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, false);
}
return store_bits(dst, src + ' + ' + addr, 8, false);
},
'sst.h': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, true);
}
return store_bits(dst, src + ' + ' + addr, 16, true);
},
'sst.hu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, false);
}
return store_bits(dst, src + ' + ' + addr, 16, false);
},
'sst.w': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 32, false);
}
return store_bits(dst, src + ' + ' + addr, 32, false);
},
'st.b': function(instr) {
// st.X , r14, 0x6c36[r4]
// ["st.X","r14","0x6c36","r4"]
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, true);
}
return store_bits(dst, src + ' + ' + addr, 8, true);
},
'st.bu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 8, false);
}
return store_bits(dst, src + ' + ' + addr, 8, false);
},
'st.h': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, true);
}
return store_bits(dst, src + ' + ' + addr, 16, true);
},
'st.hu': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 16, false);
}
return store_bits(dst, src + ' + ' + addr, 16, false);
},
'st.w': function(instr) {
var dst = instr.parsed.opd[0];
var addr = instr.parsed.opd[1];
var src = instr.parsed.opd[2];
if (src == '0') {
return store_bits(dst, addr, 32, false);
}
return store_bits(dst, src + ' + ' + addr, 32, false);
},
sub: function(instr) {
return _common_math(instr.parsed, Base.subtract);
},
subr: function(instr) {
return _common_math(instr.parsed, Base.subtract, true);
},
sxb: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.extend(instr.parsed.opd[1], instr.parsed.opd[0], 32);
},
sxh: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
return Base.extend(instr.parsed.opd[1], instr.parsed.opd[0], 32);
},
tst: function(instr, context, instructions) {
var e = instr.parsed;
context.cond.a = (e.opd[0] == e.opd[1]) ? e.opd[1] : "(" + e.opd[1] + " & " + e.opd[0] + ")";
context.cond.b = '0';
return Base.nop();
},
xor: function(instr) {
return _common_math(instr.parsed, Base.xor);
},
xori: function(instr) {
if (instr.parsed.opd[2] == '0') {
return Base.nop();
}
return Base.xor(instr.parsed.opd[2], instr.parsed.opd[1], instr.parsed.opd[0]);
},
zxb: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
var a = Variable.local(instr.parsed.opd[0], 32, false);
return Base.assign(instr.parsed.opd[1], a);
},
zxh: function(instr) {
if (instr.parsed.opd[1] == '0') {
return Base.nop();
}
var a = Variable.local(instr.parsed.opd[0], 32, false);
return Base.assign(instr.parsed.opd[1], a);
},
invalid: function() {
return Base.nop();
}
},
parse: function(assembly) {
var ret = assembly.replace(/\[|\]/g, ' ').replace(/,/g, ' ');
ret = ret.replace(/\{|\}/g, ' ').replace(/\s+/g, ' ');
ret = ret.trim().replace(/\br0\b/g, '0').split(' ');
return {
mnem: ret.shift(),
opd: ret
};
},
context: function() {
return {
cond: {
a: '?',
b: '?'
},
leave: false,
vars: []
};
},
localvars: function(context) {
return [];
},
globalvars: function(context) {
return [];
},
arguments: function(context) {
return [];
},
returns: function(context) {
return 'void';
}
};
});
-546
View File
@@ -1,546 +0,0 @@
// SPDX-FileCopyrightText: 2018-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
var Base = require('libdec/core/base');
var Variable = require('libdec/core/variable');
var Extra = require('libdec/core/extra');
var _memory_name = "_memory";
var _to_argument = function(wasm_var) {
return wasm_var.toString('arg');
};
var WasmVar = function(name, type, instr) {
this.name = name;
this.type = type;
this.instr = instr;
this.toString = function(s) {
if (s == 'arg') {
return this.type + ' ' + this.name;
}
return this.name;
};
};
var StackVar = function(type, instr) {
return new WasmVar(Variable.uniqueName('stack'), type, instr);
};
var _is_next_a_set = function(instr, instructions) {
var pos = instructions.indexOf(instr) + 1;
if (!instructions[pos]) {
return false;
}
var mnem = instructions[pos].parsed.mnem;
return mnem == 'set_local' || mnem == 'set_global' ? pos : -1;
};
var _is_next_local = function(instr, instructions) {
var pos = instructions.indexOf(instr) + 1;
if (!instructions[pos]) {
return false;
}
var mnem = instructions[pos].parsed.mnem;
return mnem == 'set_local' ? pos : -1;
};
var _is_previous_call = function(instr, instructions) {
var pos = instructions.indexOf(instr) - 1;
if (!instructions[pos]) {
return false;
}
var mnem = instructions[pos].parsed.mnem;
return mnem == 'call' ? pos : -1;
};
var _set_local = function(instr, context, instructions, type, allow_args) {
var pos = _is_next_local(instr, instructions);
var name = allow_args ? 'arg_' : 'local';
var n = '';
if (pos < 0) {
n = instr.parsed.opd[0];
if (!context.local[n]) {
name += n;
context.local[n] = new WasmVar(name, type, instr);
if (allow_args) {
context.input[n] = context.local[n];
}
}
return context.local[n];
}
n = instructions[pos].parsed.opd[0];
if (!context.local[n]) {
name += n;
context.local[n] = new WasmVar(name, type, instr);
if (allow_args) {
context.input[n] = context.local[n];
}
}
return context.local[n];
};
var _set_global = function(instr, context, instructions, type) {
var n = instr.parsed.opd[0].trim();
if (!context.global[n]) {
context.global[n] = new WasmVar('global_' + instr.parsed.opd[0], type, instr);
}
return context.global[n];
};
var _bits = function(o) {
if (typeof o == 'object') {
o = o.parsed.type;
}
switch (o) {
case 'f32':
return 32;
case 'f64':
return 64;
case 'i64':
return 64;
default:
return 32;
}
};
var _type = function(o, unsigned) {
if (typeof o == 'object') {
o = o.parsed.type;
}
switch (o) {
case 'f32':
return 'float';
case 'f64':
return 'double';
case 'i64':
return unsigned ? 'uint64_t' : 'int64_t';
default:
return unsigned ? 'uint32_t' : 'int32_t';
}
};
var _remove_const = function(instr, instructions, stackval) {
if (stackval && instructions.indexOf(stackval.instr) == (instructions.indexOf(instr) - 1) && stackval.instr.parsed.mnem == 'const') {
stackval.instr.valid = false;
// <type>.const <N>
return stackval.instr.parsed.opd[0];
}
return stackval;
};
var _math = function(instr, context, instructions, type, op) {
var source_b = context.stack.pop();
source_b = _remove_const(instr, instructions, source_b);
var source_a = context.stack.pop();
source_a.type = type;
source_b.type = type;
var pos = _is_next_a_set(instr, instructions);
var destination = StackVar(type, instr);
context.stack.push(destination); // push must happen.
if (pos < 0) {
return op(destination.toString(), source_a.toString(), source_b.toString());
}
var next_set = instructions[pos];
next_set.valid = false;
if (next_set.parsed.mnem == 'set_local') {
destination = _set_local(next_set, context, instructions, 'int32_t', false);
} else {
destination = _set_global(next_set, context, instructions, 'int32_t');
}
return op(destination.toString(), source_a.toString(), source_b.toString());
};
var _cmp = {
eq: 'EQ',
ne: 'NE',
eqz: 'EQ',
nez: 'NE',
gt_s: 'GT',
gt_u: 'GT',
ge_s: 'GE',
ge_u: 'GE',
lt_s: 'LT',
lt_u: 'LT',
le_s: 'LE',
le_u: 'LE',
gt: 'GT',
ge: 'GE',
lt: 'LT',
le: 'LE'
};
var _conditional = function(instr, context, instructions) {
var cond = {};
cond.b = context.stack.pop().toString();
cond.a = context.stack.pop().toString();
if (!cond.a) {
cond.a = '?';
}
if (!cond.b) {
cond.b = '?';
}
cond.cmp = _cmp[instr.parsed.mnem];
context.condstack.push(cond);
return Base.nop();
};
var _conditional_zero = function(instr, context, instructions) {
var cond = {};
cond.b = '0';
cond.a = context.stack.pop().toString();
if (!cond.a) {
cond.a = '?';
}
cond.cmp = _cmp[instr.parsed.mnem];
context.condstack.push(cond);
return Base.nop();
};
var _set_instruction_conditional = function(instr, context) {
var cond = context.condstack.pop();
if (!cond) {
var arg = context.stack.pop();
if (!arg) {
arg = '?';
}
instr.conditional(arg.toString(), '0', 'NE');
} else {
instr.conditional(cond.a, cond.b, cond.cmp);
}
};
var _common_load = function(instr, context) {
context.memory = true;
var offset = instr.parsed.opd[instr.parsed.opd.length - 1];
var pointer = context.stack.pop().toString();
var register = StackVar(_type(instr), instr);
context.stack.push(register);
if (offset != '0') {
var bits = instr.parsed.mnem.match(/\d+/) || ["32"];
bits = parseInt(bits[0]) / 8;
pointer += ' + ' + (parseInt(offset) / bits).toString();
}
pointer = _memory_name + ' + ' + pointer;
return Base.read_memory(pointer, register.toString(), _bits(instr), instr.parsed.mnem.endsWith('_s'));
};
var _common_store = function(instr, context) {
context.memory = true;
var offset = instr.parsed.opd[instr.parsed.opd.length - 1];
var register = context.stack.pop().toString();
var pointer = context.stack.pop().toString();
var bits = instr.parsed.mnem.match(/\d+/) || ["32"];
bits = parseInt(bits[0]);
if (offset != '0') {
pointer += ' + ' + (parseInt(offset) / (bits / 8)).toString();
}
pointer = _memory_name + ' + ' + pointer;
return Base.write_memory(pointer, register.toString(), bits, false);
};
var _wasm_arch = {
instructions: {
eq: _conditional,
ne: _conditional,
eqz: _conditional_zero,
nez: _conditional_zero,
gt_s: _conditional,
gt_u: _conditional,
ge_s: _conditional,
ge_u: _conditional,
lt_s: _conditional,
lt_u: _conditional,
le_s: _conditional,
le_u: _conditional,
gt: _conditional,
ge: _conditional,
lt: _conditional,
le: _conditional,
const: function(instr, context, instructions) {
var s = StackVar('const ' + _type(instr), instr);
context.stack.push(s);
var num = parseInt(instr.parsed.opd[0]);
if (num > 1023) {
num = '0x' + num.toString(16);
}
return Base.assign(s.toString(), num.toString());
},
load: _common_load,
load8_s: _common_load,
load8_u: _common_load,
load16_s: _common_load,
load16_u: _common_load,
store: _common_store,
store8: _common_store,
store16: _common_store,
store32: _common_store,
add: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.add);
},
and: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.and);
},
div_s: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.divide);
},
div_u: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr, true), Base.divide);
},
extend_s: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr));
}
return Base.extend(s.toString(), b.toString(), _type(instr));
},
extend_u: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
mul: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.multiply);
},
or: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.or);
},
reinterpret: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.assign(s.toString('arg'), b.toString());
}
return Base.assign(s.toString(), b.toString());
},
rem_s: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.module);
},
rem_u: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr, true), Base.module);
},
shl: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.shift_left);
},
shr_s: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.shift_right);
},
shr_u: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr, true), Base.shift_right);
},
sub: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.subtract);
},
wrap: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
trunc_s: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
trunc_u: function(instr, context, instructions) {
var s = _set_local(instr, context, instructions, _type(instr), false);
var b = context.stack.pop();
context.stack.push(s);
if (_is_next_local(instr, instructions) < 0) {
return Base.extend(s.toString('arg'), b.toString(), _type(instr, true));
}
return Base.extend(s.toString(), b.toString(), _type(instr, true));
},
xor: function(instr, context, instructions) {
return _math(instr, context, instructions, _type(instr), Base.xor);
},
get_global: function(instr, context, instructions) {
var dst = _set_global(instr, context, instructions, 'int32_t');
context.stack.push(dst);
return Base.nop();
},
set_global: function(instr, context, instructions) {
var dst = _set_global(instr, context, instructions, 'int32_t');
var arg = context.stack.pop();
return Base.assign(dst.toString(), arg ? arg.toString() : "?");
},
get_local: function(instr, context, instructions) {
context.stack.push(_set_local(instr, context, instructions, 'int32_t', true));
return Base.nop();
},
set_local: function(instr, context, instructions) {
var dst = _set_local(instr, context, instructions, 'int32_t', false);
var pos = _is_previous_call(instr, instructions);
if (pos > -1) {
var call = instructions[pos];
call.code = Base.assign(dst.toString(), call.code);
return Base.nop();
}
var arg = context.stack.pop();
return Base.assign(dst.toString(), arg ? arg.toString() : "?");
},
tee_local: function(instr, context, instructions) {
var dst = _set_local(instr, context, instructions, 'int32_t', true);
var pos = _is_previous_call(instr, instructions);
if (pos > -1) {
var call = instructions[pos];
call.code = Base.assign(dst.toString(), call.code);
return Base.nop();
}
var arg = context.stack[context.stack.length - 1];
return Base.assign(dst.toString(), arg.toString());
},
drop: function(instr, context, instructions) {
_remove_const(instr, instructions, context.stack.pop());
return Base.nop();
},
call: function(instr, context, instructions) {
var args = [];
for (var i = instructions.indexOf(instr) - 1; i >= 0; i--) {
var previous = instructions[i].parsed.mnem;
if (!previous.startsWith('get_') && previous != 'const') {
break;
}
args.unshift(context.stack.pop());
}
if (instr.parsed.opd[0].match(/^\d+$/)) {
return Base.call('fcn_' + instr.parsed.opd[0], args);
}
return Base.call(instr.parsed.opd[0], args);
},
return: function(instr, context, instructions) {
var ret = null;
if (context.stack.length > 0) {
if (context.stack.length > 1) {
Global.warning('[wasm] stack len is not zero: ' + context.stack.length);
}
context.returned = context.stack.pop();
ret = _remove_const(instr, instructions, context.returned);
if (!Extra.is.string(ret)) {
ret = context.returned.toString();
}
}
return Base.return(ret);
},
'if': function(instr, context, instructions) {
_set_instruction_conditional(instr, context);
return Base.nop();
},
br_if: function(instr, context, instructions) {
_set_instruction_conditional(instr, context);
return Base.nop();
},
'else': function(instr, context, instructions) {
return Base.nop();
},
block: function(instr, context, instructions) {
return Base.nop();
},
loop: function(instr, context, instructions) {
return Base.nop();
},
end: function(instr, context, instructions) {
if (instr.jump && instr.jump.lte(instr.location)) {
_set_instruction_conditional(instr, context);
} else {
var curidx = instructions.indexOf(instr);
if (curidx == (instructions.length - 1)) {
var ret = null;
if (context.stack.length > 0) {
if (context.stack.length > 1) {
Global.warning('[wasm] stack len is not zero: ' + context.stack.length);
}
context.returned = context.stack.pop();
ret = _remove_const(instr, instructions, context.returned);
if (!Extra.is.string(ret)) {
ret = ret.toString();
}
}
return Base.return(ret);
}
}
return Base.nop();
},
br: function(instr, context, instructions) {
return Base.nop();
},
nop: function(instr, context, instructions) {
return Base.nop();
},
invalid: function(instr, context, instructions) {
return Base.nop();
}
},
parse: function(asm) {
asm = asm.trim().replace(/\s+/g, ' ').replace(/\//g, ' ');
var type = asm.match(/[if]\d\d\./);
if (type) {
type = type[0];
asm = asm.replace(/[if]\d\d\./, '');
}
asm = asm.split(' ');
return {
type: type || 'i32',
mnem: asm.shift(),
opd: asm
};
},
context: function() {
return {
returned: null,
global: {},
input: {},
local: {},
stack: [],
condstack: [],
memory: false,
};
},
globalvars: function(context) {
var to_return = Extra.to.array(context.global).map(_to_argument);
if (context.memory) {
to_return.unshift("extern uint8_t " + _memory_name + "[]");
}
return to_return;
},
localvars: function(context) {
var vars = [];
for (var k in context.local) {
var o = context.local[k];
if (Extra.is.inObject(context.input, o) || Extra.is.inObject(context.global, o)) {
continue;
}
vars.push(o.toString('arg'));
}
return vars;
},
arguments: function(context) {
return Extra.to.array(context.input).map(_to_argument);
},
returns: function(context) {
if (context.returned) {
return context.returned.type.replace(/const\s/, '');
}
return 'void';
}
};
return _wasm_arch;
});
-2336
View File
File diff suppressed because it is too large. Load diff
-21
View File
@@ -1,21 +0,0 @@
// SPDX-FileCopyrightText: 2017-2021 Giovanni Dante Grazioli <[email protected]>
// SPDX-License-Identifier: BSD-3-Clause
(function() { // lgtm [js/useless-expression]
return {
'6502': require('libdec/arch/6502'),
'8051': require('libdec/arch/8051'),
arm: require('libdec/arch/arm'),
avr: require('libdec/arch/avr'),
dalvik: require('libdec/arch/dalvik'),
m68k: require('libdec/arch/m68k'),
mips: require('libdec/arch/mips'),
ppc: require('libdec/arch/ppc'),
riscv: require('libdec/arch/riscv'),
sh: require('libdec/arch/sh'),
sparc: require('libdec/arch/sparc'),
v850: require('libdec/arch/v850'),
wasm: require('libdec/arch/wasm'),
x86: require('libdec/arch/x86')
};
});
Loaded 100 of 155 files, more files were not shown because too many files have changed in this diff. Show more