mirror of
https://github.com/radareorg/r2hermes.git
synced 2026-11-10 17:41:32 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
911c520da5 | ||
|
|
5d77df7091 | ||
|
|
722793f084 | ||
|
|
0b53e148fb | ||
|
|
a93ca6767d | ||
|
|
e3f5b7e560 | ||
|
|
47279d355c | ||
|
|
3b08970ce8 | ||
|
|
0566ca00a8 | ||
|
|
4bfde1f33f | ||
|
|
6a243fbc1e | ||
|
|
e073f29cb3 | ||
|
|
e7bbd96fc7 | ||
|
|
1370dc15ce | ||
|
|
d448e54eb8 | ||
|
|
5faf591cb0 | ||
|
|
a9e5b02a47 | ||
|
|
ce854d747f | ||
|
|
dfc3a0f788 | ||
|
|
0e2bdf4171 | ||
|
|
fbeb335107 | ||
|
|
1021280afe | ||
|
|
9089923bf8 | ||
|
|
6ef311dbf7 | ||
|
|
d89306435e | ||
|
|
9eebb355ec | ||
|
|
e80509d031 | ||
|
|
16d01a2f15 | ||
|
|
09752c456f | ||
|
|
5d647b945f | ||
|
|
514ed8e7f8 | ||
|
|
4863d19818 |
No files matched your search
@@ -4,8 +4,5 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "##build "
|
||||
prefix-development: "##build "
|
||||
labels:
|
||||
- buildsystem
|
||||
+66
-15
@@ -1,5 +1,8 @@
|
||||
name: CI
|
||||
|
||||
env:
|
||||
R2V: 6.2.6
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -16,14 +19,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install build deps
|
||||
run: sudo apt-get update -y && sudo apt-get install -y build-essential autoconf automake libtool pkg-config
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v2
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
- name: Build library
|
||||
run: make
|
||||
- name: Build r2 plugin
|
||||
@@ -52,7 +57,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -61,13 +66,15 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v2
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
- name: Build Debian package
|
||||
run: make -C dist/debian SUDO=
|
||||
|
||||
- name: Upload Debian package artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: debian-package
|
||||
path: dist/debian/*.deb
|
||||
@@ -79,10 +86,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: 3.12.x
|
||||
|
||||
@@ -93,7 +100,9 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v2
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
- name: Build and install with Meson
|
||||
shell: cmd
|
||||
@@ -122,22 +131,56 @@ jobs:
|
||||
run: |
|
||||
Compress-Archive -Path install\* -DestinationPath r2hermes-windows-x64.zip -Force
|
||||
|
||||
- name: Package r2pm binary
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force -Path bindist\plugins,bindist\bin | Out-Null
|
||||
Copy-Item install\lib\radare2\plugins\*.dll bindist\plugins
|
||||
Copy-Item install\bin\r2hermes.exe bindist\bin
|
||||
Compress-Archive -Path bindist\* -DestinationPath "r2hermes-$env:R2V-windows-x86-64.zip" -Force
|
||||
|
||||
- name: Upload Windows package artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: windows-package
|
||||
path: r2hermes-windows-x64.zip
|
||||
path: r2hermes-*.zip
|
||||
if-no-files-found: error
|
||||
|
||||
bindist:
|
||||
name: Build r2pm binary (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Install radare2
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
- name: Package r2pm binary
|
||||
run: make bindist
|
||||
|
||||
- name: Upload r2pm binary artifact
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: bindist-${{ matrix.os }}
|
||||
path: r2hermes-*.zip
|
||||
if-no-files-found: error
|
||||
|
||||
release:
|
||||
name: Create release and upload artifacts
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, debian, windows]
|
||||
needs: [build, debian, windows, bindist]
|
||||
if: needs.build.outputs.tag != ''
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -149,25 +192,33 @@ jobs:
|
||||
ls -l libhbc*
|
||||
|
||||
- name: Download Debian package artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
name: debian-package
|
||||
path: release-artifacts
|
||||
|
||||
- name: Download Windows package artifact
|
||||
uses: actions/download-artifact@v8
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
name: windows-package
|
||||
path: release-artifacts/windows
|
||||
|
||||
- name: Download r2pm binary artifacts
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
pattern: bindist-*
|
||||
merge-multiple: true
|
||||
path: release-artifacts/bindist
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/[email protected].1
|
||||
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
||||
with:
|
||||
tag_name: ${{ needs.build.outputs.tag }}
|
||||
files: |
|
||||
./libhbc-${{ needs.build.outputs.tag }}.tgz
|
||||
./release-artifacts/*.deb
|
||||
./release-artifacts/windows/*.zip
|
||||
./release-artifacts/bindist/*.zip
|
||||
make_latest: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,5 +1,8 @@
|
||||
name: Meson Build
|
||||
|
||||
env:
|
||||
R2V: 6.2.2
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch: {}
|
||||
@@ -11,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -20,7 +23,9 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v2
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
- name: Build library and r2 plugin with meson
|
||||
run: meson setup builddir && meson compile -C builddir
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Checkout TinyCC repository
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install build dependencies
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
name: Windows Build
|
||||
|
||||
env:
|
||||
R2V: 6.2.2
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch: {}
|
||||
@@ -11,10 +14,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: 3.12.x
|
||||
|
||||
@@ -25,7 +28,9 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v2
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
- name: Build and install with Meson
|
||||
shell: cmd
|
||||
@@ -55,7 +60,7 @@ jobs:
|
||||
Compress-Archive -Path install\* -DestinationPath r2hermes-windows-x64.zip -Force
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: windows-package
|
||||
path: r2hermes-windows-x64.zip
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.pmai/
|
||||
build/
|
||||
bin/
|
||||
third_party/
|
||||
@@ -8,3 +9,4 @@ third_party/
|
||||
test/bins
|
||||
*.swp
|
||||
include/hbc/version.h
|
||||
*.zip
|
||||
@@ -1,5 +1,9 @@
|
||||
CC?= gcc
|
||||
CFLAGS?=-Wall -Wextra -std=c11 -pedantic -O2 -fPIC -fvisibility=hidden -D_POSIX_C_SOURCE=200809L
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# macOS hides memmem() (used by r_util headers) under strict _POSIX_C_SOURCE
|
||||
CFLAGS+=-D_DARWIN_C_SOURCE
|
||||
endif
|
||||
DEBUG_FLAGS?=-g -DDEBUG -DHBC_DEBUG_LOGGING=1
|
||||
|
||||
VERSION=$(shell grep "^[[:space:]]*version:" meson.build | cut -d "'" -f 2)
|
||||
@@ -99,6 +103,7 @@ test: $(BIN_FILE) $(TEST_BIN)
|
||||
$(BIN_FILE) Ej test/bins/hbc/bespoke_eval.hbc | grep -q '"strict":false'
|
||||
$(BIN_FILE) h test/bins/hbc/bespoke_eval.hbc | grep -q 'Source Locations: 13 bytes'
|
||||
$(BIN_FILE) h test/bins/hbc/index.android.bundle | grep -q 'Source Locations: 0 bytes'
|
||||
$(BIN_FILE) s test/bins/hbc/index.android.bundle 2959 | grep -q 'name=•'
|
||||
$(BIN_FILE) libs test/bins/hbc/index.android.bundle | grep -q 'react-native'
|
||||
|
||||
r2:
|
||||
@@ -113,6 +118,43 @@ user-install user-uninstall:
|
||||
$(MAKE) -C src/r2
|
||||
$(MAKE) -C src/r2 $@
|
||||
|
||||
# Binary package for r2pm -bi: plugins/ and bin/ for this r2 version and platform
|
||||
# Binary package for r2pm -bi: plugins/ and bin/ for this r2 version and platform
|
||||
# R2PM_OS/ARCH/BITS require a recent r2pm; fall back to uname when missing
|
||||
R2PM_OS_SH=$(shell r2pm -H R2PM_OS 2>/dev/null)
|
||||
R2PM_ARCH_SH=$(shell r2pm -H R2PM_ARCH 2>/dev/null)
|
||||
R2PM_BITS_SH=$(shell r2pm -H R2PM_BITS 2>/dev/null)
|
||||
ifeq ($(R2PM_OS_SH),)
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
R2PM_OS_SH=darwin
|
||||
else
|
||||
R2PM_OS_SH=linux
|
||||
endif
|
||||
endif
|
||||
ifeq ($(R2PM_ARCH_SH),)
|
||||
ifeq ($(shell uname -m),x86_64)
|
||||
R2PM_ARCH_SH=x86
|
||||
else ifeq ($(shell uname -m),aarch64)
|
||||
R2PM_ARCH_SH=arm
|
||||
else ifeq ($(shell uname -m),arm64)
|
||||
R2PM_ARCH_SH=arm
|
||||
else
|
||||
R2PM_ARCH_SH=$(shell uname -m)
|
||||
endif
|
||||
endif
|
||||
ifeq ($(R2PM_BITS_SH),)
|
||||
R2PM_BITS_SH=64
|
||||
endif
|
||||
BINDIST_ZIP=r2hermes-$(shell r2 -qv)-$(R2PM_OS_SH)-$(R2PM_ARCH_SH)-$(R2PM_BITS_SH).zip
|
||||
|
||||
bindist: all
|
||||
$(MAKE) -C src/r2
|
||||
rm -rf $(BUILD_DIR)/bindist $(BINDIST_ZIP)
|
||||
$(MAKE) -C src/r2 user-install R2_PLUGDIR=$(CURDIR)/$(BUILD_DIR)/bindist/plugins
|
||||
mkdir -p $(BUILD_DIR)/bindist/bin
|
||||
cp -f $(BIN_FILE) $(BUILD_DIR)/bindist/bin/
|
||||
cd $(BUILD_DIR)/bindist && zip -r $(CURDIR)/$(BINDIST_ZIP) plugins bin
|
||||
|
||||
$(VH):
|
||||
@mkdir -p $(dir $@)
|
||||
echo '#ifndef LIBHBC_VERSION' > $@
|
||||
@@ -122,4 +164,4 @@ $(VH):
|
||||
echo '#define LIBHBC_VERSION_PATCH "$(shell echo $(VERSION) | cut -d . -f 3)"' >> $@
|
||||
echo '#endif' >> $@
|
||||
|
||||
.PHONY: r2 test test2 all clean debug asan
|
||||
.PHONY: r2 test test2 all clean debug asan bindist
|
||||
@@ -81,12 +81,30 @@ Usage: pd:h[subcommand]
|
||||
[0x00000000]> r2hermes-?
|
||||
Usage: r2hermes[-arg] # see also pd:h for decompilation
|
||||
r2hermes-h - help message (same as r2hermes-?, see pd:h? too)
|
||||
r2hermes-A - Import symbols and entrypoints
|
||||
r2hermes-AA - Also import strings and SLP literal comments/xrefs
|
||||
r2hermes-AAA - Also analyze bytecode references
|
||||
r2hermes-AAAA - Also perform full analysis (aaa)
|
||||
r2hermes-E[jq] - List direct eval instruction sites (j=JSON, q=addresses only)
|
||||
r2hermes-H - Show file information and hash status
|
||||
r2hermes-L[?] - SLP literal cache: list/scan/reset/format/toggle
|
||||
r2hermes-S[jr?] - emit SBOM from SLP literals (j=CycloneDX JSON, r=raw input)
|
||||
```
|
||||
|
||||
The analysis levels are cumulative, like `r2flutter-A` and `r2unity-A`.
|
||||
Use `r2hermes-A` to import symbols and entrypoint flags, and `r2hermes-AA` to
|
||||
also import string flags and metadata, plus SLP literal flags, comments, and
|
||||
constructor references. `r2hermes-AAA` adds reference analysis over each
|
||||
function's bytecode range; `r2hermes-AAAA` additionally runs `aaa` to analyze
|
||||
functions and control flow. Addresses follow `io.va`, and the commands preserve
|
||||
the current seek and flagspace. Use `r2hermes-A?` for analysis help.
|
||||
|
||||
`r2hermes-L` lists the constructor instruction addresses after `xrefs=`.
|
||||
Object literal addresses point to their serialized values; their keys or shapes
|
||||
can be shared by objects with different values. Pools can also share values, so
|
||||
`r2hermes-Lx <addr>` lists every matching entry. Use the constructor addresses
|
||||
on each row to navigate to that specific object. Text output follows `io.va`.
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <hbc/opcodes.h>
|
||||
#include <hbc/parser.h>
|
||||
|
||||
/* Registers reserved by Hermes above an outgoing call's this/argument window. */
|
||||
#define HBC_CALL_FRAME_RESERVED 6
|
||||
|
||||
/* Parsed instruction */
|
||||
typedef struct {
|
||||
const Instruction *inst;
|
||||
|
||||
@@ -57,14 +57,33 @@ typedef struct HBCStringMeta {
|
||||
HBCStringKind kind;
|
||||
} HBCStringMeta;
|
||||
|
||||
typedef enum {
|
||||
HBC_FUNCTION_NONE = 0,
|
||||
HBC_FUNCTION_ASYNC = 1u << 0,
|
||||
HBC_FUNCTION_GENERATOR = 1u << 1
|
||||
} HBCFunctionFlags;
|
||||
|
||||
/* Function metadata structure */
|
||||
typedef struct {
|
||||
const char *name; // Valid while provider is alive; caller must not free
|
||||
u32 offset; // Bytecode offset in file
|
||||
u32 size; // Size in bytes
|
||||
u32 param_count; // Number of parameters
|
||||
u32 flags; // HBCFunctionFlags
|
||||
} HBCFunc;
|
||||
|
||||
/* Function-relative exception-handler range. */
|
||||
typedef struct {
|
||||
u32 start;
|
||||
u32 end;
|
||||
u32 target;
|
||||
} HBCExceptionHandler;
|
||||
|
||||
typedef struct {
|
||||
HBCExceptionHandler *handlers;
|
||||
u32 count;
|
||||
} HBCExceptionHandlerArray;
|
||||
|
||||
typedef struct {
|
||||
u32 function_id;
|
||||
u32 address; // File-absolute bytecode address
|
||||
@@ -254,6 +273,13 @@ HBC_API Result hbc_get_header(HBC *hbc, HBCHeader *out);
|
||||
*/
|
||||
HBC_API Result hbc_get_function_info(HBC *hbc, u32 function_id, HBCFunc *out);
|
||||
|
||||
/** Get a copy of the exception handlers for one function. */
|
||||
HBC_API Result hbc_get_function_exception_handlers(HBC *hbc, u32 function_id, HBCExceptionHandlerArray *out);
|
||||
HBC_API void hbc_free_exception_handlers(HBCExceptionHandlerArray *arr);
|
||||
|
||||
/** Get the register-frame size for a function without exposing parser internals. */
|
||||
HBC_API Result hbc_get_function_frame_size(HBC *hbc, u32 function_id, u32 *out);
|
||||
|
||||
/**
|
||||
* Get a string by index.
|
||||
*/
|
||||
|
||||
@@ -40,7 +40,7 @@ typedef struct {
|
||||
u32 num_items;
|
||||
u32 primary_id; /* array_id (array) or keys/shape id (object) */
|
||||
u32 secondary_id; /* values_id for objects, 0 for arrays */
|
||||
u32 paddr; /* absolute file offset of the literal data in the SLP pool (0 if unknown) */
|
||||
u32 paddr; /* absolute file offset of array data or object values (0 if unknown) */
|
||||
char *formatted; /* cached JS literal text; NULL if not yet formatted */
|
||||
u32 *xref_addrs; /* instruction addresses that construct this literal */
|
||||
u32 xref_count;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
project(
|
||||
'r2hermes',
|
||||
'c',
|
||||
version: '1.4.8',
|
||||
version: '1.6.2',
|
||||
license: 'MIT',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
||||
@@ -100,7 +100,7 @@ static Result u32set_init(U32Set *s, u32 max_addr) {
|
||||
if (!s) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "u32set init");
|
||||
}
|
||||
s->bitmap_size = (max_addr + 7) / 8;
|
||||
s->bitmap_size = ((u64)max_addr + 7) / 8;
|
||||
s->bitmap = (u8 *)calloc (s->bitmap_size, 1);
|
||||
if (!s->bitmap) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "u32set bitmap");
|
||||
@@ -2962,7 +2962,7 @@ Result _hbc_output_code(HermesDecompiler *state, DecompiledFunctionBody *functio
|
||||
for (HbcTokenString *si_iter = R_VEC_START_ITER (&function_body->statements); si_iter != R_VEC_END_ITER (&function_body->statements); si_iter++) {
|
||||
size_t si = (size_t) (si_iter - R_VEC_START_ITER (&function_body->statements));
|
||||
/* Stop when budget exhausted or earlier phase (pass2) flagged it. */
|
||||
if (state->output_truncated || (state->options.max_output_bytes > 0 && r_strbuf_length (out) >= state->options.max_output_bytes)) {
|
||||
if (state->output_truncated || (state->options.max_output_bytes > 0 && r_strbuf_length (out) >= (size_t)state->options.max_output_bytes)) {
|
||||
state->output_truncated = true;
|
||||
if (!state->truncation_marker_emitted) {
|
||||
state->truncation_marker_emitted = true;
|
||||
|
||||
@@ -234,8 +234,6 @@ static Result emit_call_fixed(HbcTokenString *out, const ParsedInstruction *insn
|
||||
|
||||
/* Hermes reserves this many frame-header registers at the very top of a
|
||||
* function's register frame; an outgoing call's `this`+args sit just below. */
|
||||
#define HBC_CALL_FRAME_RESERVED 6
|
||||
|
||||
/* Variable-arity Call/Construct. Hermes places the call's argument registers at
|
||||
* the top of the caller's frame, below the reserved header: `this` at
|
||||
* frame_size-1-RESERVED, the explicit arguments descending below it.
|
||||
|
||||
+144
-4
@@ -15,6 +15,15 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
u32 source;
|
||||
u32 target;
|
||||
} HBCFunctionEdge;
|
||||
|
||||
R_VEC_TYPE(RVecHBCFunctionEdge, HBCFunctionEdge)
|
||||
|
||||
static size_t decode_operands(const Instruction *inst, const u8 *bytes, size_t len, u32 values[6]);
|
||||
|
||||
/* ============================================================================
|
||||
* HBC - Direct File Access API Implementation
|
||||
* ============================================================================ */
|
||||
@@ -127,6 +136,7 @@ void hbc_close(HBC *hbc) {
|
||||
return;
|
||||
}
|
||||
hbc_literals_reset (hbc);
|
||||
free (hbc->function_flags);
|
||||
_hbc_reader_cleanup (&hbc->reader);
|
||||
free (hbc);
|
||||
}
|
||||
@@ -153,6 +163,89 @@ Result hbc_get_header(HBC *hbc, HBCHeader *out) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
static bool opcode_is(const Instruction *insn, const char *name, const char *long_name) {
|
||||
const char *mnemonic = insn? insn->name: NULL;
|
||||
return mnemonic && (!strcmp (mnemonic, name) || !strcmp (mnemonic, long_name));
|
||||
}
|
||||
|
||||
static void add_function_edge(RVecHBCFunctionEdge *edges, u32 source, u32 target) {
|
||||
HBCFunctionEdge edge = { .source = source, .target = target };
|
||||
RVecHBCFunctionEdge_push_back (edges, &edge);
|
||||
}
|
||||
|
||||
static void hbc_ensure_function_flags(HBC *hbc) {
|
||||
if (!hbc || hbc->function_flags_ready) {
|
||||
return;
|
||||
}
|
||||
hbc->function_flags_ready = true;
|
||||
const u32 count = hbc->reader.header.functionCount;
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
hbc->function_flags = (u32 *)calloc (count, sizeof (u32));
|
||||
if (!hbc->function_flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
RVecHBCFunctionEdge edges;
|
||||
RVecHBCFunctionEdge_init (&edges);
|
||||
const HBCISA isa = hbc_isa_getv (hbc->reader.header.version);
|
||||
for (u32 function_id = 0; function_id < count; function_id++) {
|
||||
const u8 *code = NULL;
|
||||
u32 size = 0;
|
||||
if (hbc_get_function_bytecode (hbc, function_id, &code, &size).code != RESULT_SUCCESS || !code) {
|
||||
continue;
|
||||
}
|
||||
for (u32 pc = 0; pc < size;) {
|
||||
const u8 opcode = code[pc];
|
||||
const Instruction *insn = opcode < isa.count? &isa.instructions[opcode]: NULL;
|
||||
if (!insn || !insn->name || !insn->binary_size) {
|
||||
break;
|
||||
}
|
||||
u32 values[6];
|
||||
const size_t decoded_size = decode_operands (insn, code + pc, size - pc, values);
|
||||
if (!decoded_size) {
|
||||
break;
|
||||
}
|
||||
const u32 target = values[2];
|
||||
if (target >= count) {
|
||||
pc += (u32)decoded_size;
|
||||
continue;
|
||||
}
|
||||
if (opcode_is (insn, "create_async_closure", "create_async_closure_long_index")) {
|
||||
hbc->function_flags[target] |= HBC_FUNCTION_ASYNC;
|
||||
} else if (opcode_is (insn, "create_generator_closure", "create_generator_closure_long_index")) {
|
||||
hbc->function_flags[target] |= HBC_FUNCTION_GENERATOR;
|
||||
add_function_edge (&edges, function_id, target);
|
||||
} else if (opcode_is (insn, "create_generator", "create_generator_long_index")) {
|
||||
hbc->function_flags[function_id] |= HBC_FUNCTION_GENERATOR;
|
||||
hbc->function_flags[target] |= HBC_FUNCTION_GENERATOR;
|
||||
add_function_edge (&edges, function_id, target);
|
||||
}
|
||||
pc += (u32)decoded_size;
|
||||
}
|
||||
}
|
||||
|
||||
bool changed;
|
||||
do {
|
||||
changed = false;
|
||||
HBCFunctionEdge *edge;
|
||||
R_VEC_FOREACH (&edges, edge) {
|
||||
if ((hbc->function_flags[edge->source] & HBC_FUNCTION_ASYNC) &&
|
||||
! (hbc->function_flags[edge->target] & HBC_FUNCTION_ASYNC)) {
|
||||
hbc->function_flags[edge->target] |= HBC_FUNCTION_ASYNC;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
if (hbc->function_flags[i] & HBC_FUNCTION_ASYNC) {
|
||||
hbc->function_flags[i] &= ~HBC_FUNCTION_GENERATOR;
|
||||
}
|
||||
}
|
||||
RVecHBCFunctionEdge_fini (&edges);
|
||||
}
|
||||
|
||||
Result hbc_get_function_info(HBC *hbc, u32 function_id, HBCFunc *out) {
|
||||
if (!hbc || !out) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid arguments");
|
||||
@@ -173,6 +266,57 @@ Result hbc_get_function_info(HBC *hbc, u32 function_id, HBCFunc *out) {
|
||||
out->offset = fh->offset;
|
||||
out->size = fh->bytecodeSizeInBytes;
|
||||
out->param_count = fh->paramCount;
|
||||
hbc_ensure_function_flags (hbc);
|
||||
out->flags = hbc->function_flags? hbc->function_flags[function_id]: HBC_FUNCTION_NONE;
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
Result hbc_get_function_exception_handlers(HBC *hbc, u32 function_id, HBCExceptionHandlerArray *out) {
|
||||
if (!hbc || !out) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid arguments");
|
||||
}
|
||||
out->handlers = NULL;
|
||||
out->count = 0;
|
||||
HBCReader *reader = &hbc->reader;
|
||||
if (!reader->function_headers || function_id >= reader->header.functionCount) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Function ID out of range");
|
||||
}
|
||||
if (!reader->function_id_to_exc_handlers) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
const ExceptionHandlerList *source = &reader->function_id_to_exc_handlers[function_id];
|
||||
if (!source->count) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
if (!source->handlers) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_DATA, "Invalid exception handler table");
|
||||
}
|
||||
HBCExceptionHandler *handlers = (HBCExceptionHandler *)calloc (source->count, sizeof (HBCExceptionHandler));
|
||||
if (!handlers) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "Cannot allocate exception handlers");
|
||||
}
|
||||
for (u32 i = 0; i < source->count; i++) {
|
||||
handlers[i].start = source->handlers[i].start;
|
||||
handlers[i].end = source->handlers[i].end;
|
||||
handlers[i].target = source->handlers[i].target;
|
||||
}
|
||||
out->handlers = handlers;
|
||||
out->count = source->count;
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
void hbc_free_exception_handlers(HBCExceptionHandlerArray *arr) {
|
||||
if (arr) {
|
||||
R_FREE (arr->handlers);
|
||||
arr->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Result hbc_get_function_frame_size(HBC *hbc, u32 function_id, u32 *out) {
|
||||
if (!hbc || !out || !hbc->reader.function_headers || function_id >= hbc->reader.header.functionCount) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid arguments");
|
||||
}
|
||||
*out = hbc->reader.function_headers[function_id].frameSize;
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
@@ -721,10 +865,6 @@ static char *build_literal_comment(HBCReader *reader, const char *mnemonic, cons
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Read each operand by type into values[6], little-endian with sign-extension
|
||||
* for relative addresses; returns total instruction size, or 0 if truncated. */
|
||||
static size_t decode_operands(const Instruction *inst, const u8 *bytes, size_t len, u32 values[6]);
|
||||
|
||||
Result hbc_dec(const HBCDecodeCtx *ctx, HBCInsnInfo *out) {
|
||||
if (!ctx || !out) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "Invalid context");
|
||||
|
||||
@@ -31,6 +31,8 @@ struct HBC {
|
||||
u32 string_count;
|
||||
const char **strings;
|
||||
u32 function_count;
|
||||
u32 *function_flags;
|
||||
bool function_flags_ready;
|
||||
HBCLiteralCache lit_cache;
|
||||
};
|
||||
|
||||
|
||||
+5
-14
@@ -133,9 +133,8 @@ static HBCLiteralEntry *cache_find(HBCLiteralCache *c, HBCLiteralKind kind, u32
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Compute paddr for an entry based on its kind/primary_id. For v97+ objects,
|
||||
* primary_id is a shape index — resolve via the shape table. */
|
||||
static u32 entry_paddr(HBC *hbc, HBCLiteralKind kind, u32 primary_id) {
|
||||
/* Anchor objects at their values, not their shared keys/shape. */
|
||||
static u32 entry_paddr(HBC *hbc, HBCLiteralKind kind, u32 primary_id, u32 secondary_id) {
|
||||
const HBCReader *r = &hbc->reader;
|
||||
if (kind == HBC_LIT_ARRAY) {
|
||||
if (!r->arrays) {
|
||||
@@ -146,18 +145,10 @@ static u32 entry_paddr(HBC *hbc, HBCLiteralKind kind, u32 primary_id) {
|
||||
}
|
||||
return r->arrays_paddr + primary_id;
|
||||
}
|
||||
/* object */
|
||||
if (r->header.version >= 97 && r->object_shapes && primary_id < r->object_shape_count) {
|
||||
u32 key_off = r->object_shapes[primary_id].key_buffer_offset;
|
||||
if (r->object_keys && key_off < r->header.objKeyBufferSize) {
|
||||
return r->object_keys_paddr + key_off;
|
||||
}
|
||||
if (!r->object_values || secondary_id >= r->header.objValueBufferSize) {
|
||||
return 0;
|
||||
}
|
||||
if (!r->object_keys || primary_id >= r->header.objKeyBufferSize) {
|
||||
return 0;
|
||||
}
|
||||
return r->object_keys_paddr + primary_id;
|
||||
return r->object_values_paddr + secondary_id;
|
||||
}
|
||||
|
||||
static Result cache_get_or_create(HBC *hbc, HBCLiteralKind kind, u32 num_items, u32 primary_id, u32 secondary_id, bool format, HBCLiteralEntry **out_entry) {
|
||||
@@ -182,7 +173,7 @@ static Result cache_get_or_create(HBC *hbc, HBCLiteralKind kind, u32 num_items,
|
||||
e->num_items = num_items;
|
||||
e->primary_id = primary_id;
|
||||
e->secondary_id = secondary_id;
|
||||
e->paddr = entry_paddr (hbc, kind, primary_id);
|
||||
e->paddr = entry_paddr (hbc, kind, primary_id, secondary_id);
|
||||
if (format) {
|
||||
char *txt = NULL;
|
||||
Result fr = format_raw_impl (&hbc->reader, kind, num_items, primary_id, secondary_id, &txt);
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v51[167] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v58[176] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v59[177] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v61[177] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v62[177] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v68[177] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v69[177] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v70[177] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v72[177] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,8 +87,8 @@ static const Instruction k_instructions_v73[180] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -81,14 +81,14 @@ static const Instruction k_instructions_v76[256] = {
|
||||
[74] = { "call", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[75] = { "construct", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[76] = { "call1", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[77] = { "call_direct", { { R8, 0 }, { U8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[77] = { "call_direct", { { R8, 0 }, { U8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[78] = { "call2", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[79] = { "call3", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 } }, 6 },
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[86] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
@@ -98,10 +98,10 @@ static const Instruction k_instructions_v76[256] = {
|
||||
[91] = { "async_break_check", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[92] = { "profile_point", { { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[93] = { "unreachable", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[94] = { "create_closure", { { R8, 0 }, { R8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[95] = { "create_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[96] = { "create_generator_closure", { { R8, 0 }, { R8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[97] = { "create_generator_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[94] = { "create_closure", { { R8, 0 }, { R8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[95] = { "create_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[96] = { "create_generator_closure", { { R8, 0 }, { R8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[97] = { "create_generator_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[98] = { "create_this", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[99] = { "select_object", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[100] = { "load_param", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
@@ -129,8 +129,8 @@ static const Instruction k_instructions_v76[256] = {
|
||||
[122] = { "start_generator", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[123] = { "resume_generator", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[124] = { "complete_generator", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[125] = { "create_generator", { { R8, 0 }, { R8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[126] = { "create_generator_long_index", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[125] = { "create_generator", { { R8, 0 }, { R8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[126] = { "create_generator_long_index", { { R8, 0 }, { R8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[127] = { "iterator_begin", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[128] = { "iterator_next", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[129] = { "iterator_close", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,9 +87,9 @@ static const Instruction k_instructions_v80[181] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[88] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,9 +87,9 @@ static const Instruction k_instructions_v81[183] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[87] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[88] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -87,10 +87,10 @@ static const Instruction k_instructions_v82[185] = {
|
||||
[80] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[81] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[82] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[83] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[85] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[87] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[88] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[89] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -88,10 +88,10 @@ static const Instruction k_instructions_v83[185] = {
|
||||
[81] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[82] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[86] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[84] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[86] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[88] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[89] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[90] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
+13
-13
@@ -82,16 +82,16 @@ static const Instruction k_instructions_v84[256] = {
|
||||
[75] = { "call", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[76] = { "construct", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[77] = { "call1", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[78] = { "call_direct", { { R8, 0 }, { U8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[78] = { "call_direct", { { R8, 0 }, { U8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[79] = { "call2", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[80] = { "call3", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 } }, 6 },
|
||||
[81] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[82] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[83] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[84] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[86] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[84] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[86] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[88] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[89] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[90] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
@@ -100,12 +100,12 @@ static const Instruction k_instructions_v84[256] = {
|
||||
[93] = { "debugger", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[94] = { "async_break_check", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[95] = { "profile_point", { { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[96] = { "create_closure", { { R8, 0 }, { R8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[97] = { "create_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[98] = { "create_generator_closure", { { R8, 0 }, { R8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[99] = { "create_generator_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[100] = { "create_async_closure", { { R8, 0 }, { R8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[101] = { "create_async_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[96] = { "create_closure", { { R8, 0 }, { R8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[97] = { "create_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[98] = { "create_generator_closure", { { R8, 0 }, { R8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[99] = { "create_generator_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[100] = { "create_async_closure", { { R8, 0 }, { R8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[101] = { "create_async_closure_long_index", { { R8, 0 }, { R8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[102] = { "create_this", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[103] = { "select_object", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[104] = { "load_param", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
@@ -134,8 +134,8 @@ static const Instruction k_instructions_v84[256] = {
|
||||
[127] = { "start_generator", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[128] = { "resume_generator", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[129] = { "complete_generator", { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 1 },
|
||||
[130] = { "create_generator", { { R8, 0 }, { R8, 0 }, { U16, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[131] = { "create_generator_long_index", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[130] = { "create_generator", { { R8, 0 }, { R8, 0 }, { U16, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[131] = { "create_generator_long_index", { { R8, 0 }, { R8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[132] = { "iterator_begin", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[133] = { "iterator_next", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[134] = { "iterator_close", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -90,10 +90,10 @@ static const Instruction k_instructions_v85[201] = {
|
||||
[83] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[84] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[90] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[91] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[92] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -90,10 +90,10 @@ static const Instruction k_instructions_v86[201] = {
|
||||
[83] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[84] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[90] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[91] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[92] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -90,10 +90,10 @@ static const Instruction k_instructions_v87[204] = {
|
||||
[83] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[84] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[90] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[91] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[92] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -90,10 +90,10 @@ static const Instruction k_instructions_v89[256] = {
|
||||
[83] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[84] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[90] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[91] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[92] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -90,10 +90,10 @@ static const Instruction k_instructions_v90[256] = {
|
||||
[83] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[84] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[90] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[91] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[92] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -92,10 +92,10 @@ static const Instruction k_instructions_v92[206] = {
|
||||
[85] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[86] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[92] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[93] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[94] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -90,10 +90,10 @@ static const Instruction k_instructions_v93[256] = {
|
||||
[83] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[84] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[85] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[86] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[88] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[90] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[91] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[92] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -92,10 +92,10 @@ static const Instruction k_instructions_v94[256] = {
|
||||
[85] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[86] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[92] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[93] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[94] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
|
||||
@@ -92,10 +92,10 @@ static const Instruction k_instructions_v95[256] = {
|
||||
[85] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[86] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[92] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[93] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[94] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
|
||||
@@ -92,10 +92,10 @@ static const Instruction k_instructions_v96[256] = {
|
||||
[85] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[86] = { "call_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[87] = { "construct_long", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[88] = { "call_direct_long_index", { { R8, 0 }, { U8, 0 }, { U32, OPERAND_MEANING_FUNCTION_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[89] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[90] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[91] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[92] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[93] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[94] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
|
||||
@@ -105,9 +105,9 @@ static const Instruction k_instructions_v97[200] = {
|
||||
[98] = { "call3", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 } }, 6 },
|
||||
[99] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[100] = { "call_with_new_target_long", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[101] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[102] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[103] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[101] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[102] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[103] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[104] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[105] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[106] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
|
||||
@@ -120,9 +120,9 @@ static const Instruction k_instructions_v98[219] = {
|
||||
[112] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[113] = { "call_with_new_target_long", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[114] = { "call_require", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[115] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[116] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[117] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[115] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[116] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[117] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[118] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[119] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[120] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
@@ -220,8 +220,8 @@ static const Instruction k_instructions_v98[219] = {
|
||||
[212] = { "j_strict_equal_long", { { A32, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[213] = { "j_strict_not_equal", { { A8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[214] = { "j_strict_not_equal_long", { { A32, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[215] = { "jmp_builtin_is", { { A8, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[216] = { "jmp_builtin_is_long", { { A32, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[217] = { "jmp_builtin_is_not", { { A8, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[218] = { "jmp_builtin_is_not_long", { { A32, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[215] = { "jmp_builtin_is", { { A8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[216] = { "jmp_builtin_is_long", { { A32, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[217] = { "jmp_builtin_is_not", { { A8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[218] = { "jmp_builtin_is_not_long", { { A32, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
};
|
||||
@@ -119,9 +119,9 @@ static const Instruction k_instructions_v99[223] = {
|
||||
[112] = { "call4", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 } }, 7 },
|
||||
[113] = { "call_with_new_target_long", { { R8, 0 }, { R8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 } }, 5 },
|
||||
[114] = { "call_require", { { R8, 0 }, { R8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[115] = { "call_builtin", { { R8, 0 }, { U8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[116] = { "call_builtin_long", { { R8, 0 }, { U8, 0 }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[117] = { "get_builtin_closure", { { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[115] = { "call_builtin", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[116] = { "call_builtin_long", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { U32, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[117] = { "get_builtin_closure", { { R8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 3 },
|
||||
[118] = { "ret", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[119] = { "catch", { { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 2 },
|
||||
[120] = { "direct_eval", { { R8, 0 }, { R8, 0 }, { U8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
@@ -223,8 +223,8 @@ static const Instruction k_instructions_v99[223] = {
|
||||
[216] = { "j_strict_equal_long", { { A32, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[217] = { "j_strict_not_equal", { { A8, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[218] = { "j_strict_not_equal_long", { { A32, 0 }, { R8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[219] = { "jmp_builtin_is", { { A8, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[220] = { "jmp_builtin_is_long", { { A32, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[221] = { "jmp_builtin_is_not", { { A8, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[222] = { "jmp_builtin_is_not_long", { { A32, 0 }, { U8, 0 }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[219] = { "jmp_builtin_is", { { A8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[220] = { "jmp_builtin_is_long", { { A32, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
[221] = { "jmp_builtin_is_not", { { A8, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 4 },
|
||||
[222] = { "jmp_builtin_is_not_long", { { A32, 0 }, { U8, OPERAND_MEANING_BUILTIN_ID }, { R8, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, 7 },
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
/* r2hermes - BSD - Copyright 2025-2026 - pancake */
|
||||
|
||||
#include <hbc/parser.h>
|
||||
#include <r_lib.h>
|
||||
#include <r_util/r_str.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -884,7 +886,12 @@ Result _hbc_reader_read_string_tables(HBCReader *reader) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *str = (char *)malloc (length * bpc + 1);
|
||||
size_t decoded_size = 0;
|
||||
RETURN_IF_ERROR (checked_count_size (length, is_utf16? 3: 1, &decoded_size, "Decoded string is too large"));
|
||||
if (decoded_size == SIZE_MAX) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "Decoded string is too large");
|
||||
}
|
||||
char *str = (char *)malloc (decoded_size + 1);
|
||||
if (!str) {
|
||||
free (string_storage);
|
||||
reader->string_table_storage = NULL;
|
||||
@@ -893,17 +900,20 @@ Result _hbc_reader_read_string_tables(HBCReader *reader) {
|
||||
|
||||
/* Copy string data */
|
||||
if (is_utf16) {
|
||||
/* UTF-16 string */
|
||||
/* Note: This is a simplified version that doesn't handle surrogate pairs */
|
||||
for (u32 j = 0; j < length; j++) {
|
||||
u16 c = (string_storage[offset + j * 2] | (string_storage[offset + j * 2 + 1] << 8));
|
||||
if (c < 128) {
|
||||
str[j] = (char)c;
|
||||
} else {
|
||||
str[j] = '?'; /* Replace non-ASCII with? */
|
||||
}
|
||||
/* The final flag changed from little-endian to big-endian in ABI 115. */
|
||||
#if R2_ABIVERSION >= 115
|
||||
int written = r_str_utf16_to_utf8 ((ut8 *)str, decoded_size + 1,
|
||||
string_storage + offset, length * 2, false);
|
||||
#else
|
||||
int written = r_str_utf16_to_utf8 ((ut8 *)str, decoded_size + 1,
|
||||
string_storage + offset, length * 2, true);
|
||||
#endif
|
||||
if (written < 0) {
|
||||
free (str);
|
||||
free (string_storage);
|
||||
reader->string_table_storage = NULL;
|
||||
return ERROR_RESULT (RESULT_ERROR_PARSING_FAILED, "Invalid UTF-16 string");
|
||||
}
|
||||
str[length] = '\0';
|
||||
} else {
|
||||
/* ASCII string */
|
||||
memcpy (str, string_storage + offset, length);
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ LDFLAGS += $(shell pkg-config --libs r_core 2>/dev/null || echo "$(if $(R2PM_LIN
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
EXT_SO = dylib
|
||||
CFLAGS += -D_DARWIN_C_SOURCE
|
||||
LDFLAGS += -dynamiclib -undefined dynamic_lookup
|
||||
else ifeq ($(UNAME_S),Linux)
|
||||
EXT_SO = so
|
||||
@@ -35,7 +36,7 @@ BIN_SRC = bin_hbc.c
|
||||
ASM_SRC = asm_hbc.c
|
||||
CORE_SRC = core_hbc.c
|
||||
CORE_ONE_SRC = core_hbc_one.c
|
||||
HBC_HEADERS = $(shell find ../../include -name '*.h') utils.inc.c sbom.inc.c
|
||||
HBC_HEADERS = $(shell find ../../include -name '*.h') utils.inc.c sbom.inc.c version.inc.c
|
||||
|
||||
# Object files
|
||||
ARCH_OBJ = arch_hbc.o
|
||||
|
||||
+318
-39
@@ -13,9 +13,17 @@
|
||||
#define R_ARCH_SYNTAX_CAMEL 6
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u32 frame_size;
|
||||
} HermesFunctionFrame;
|
||||
|
||||
typedef struct {
|
||||
ut32 bytecode_version; /* cached effective HBC bytecode version */
|
||||
HBC *hbc; /* Hermes state for direct access */
|
||||
HermesFunctionFrame *function_frames;
|
||||
u32 function_frame_count;
|
||||
u32 string_count;
|
||||
u32 overflow_string_count;
|
||||
const void *small_string_table;
|
||||
@@ -23,6 +31,12 @@ typedef struct {
|
||||
u64 string_storage_offset;
|
||||
} HermesArchSession;
|
||||
|
||||
static int function_frame_cmp(const void *a, const void *b) {
|
||||
const HermesFunctionFrame *fa = (const HermesFunctionFrame *)a;
|
||||
const HermesFunctionFrame *fb = (const HermesFunctionFrame *)b;
|
||||
return fa->offset < fb->offset? -1: fa->offset > fb->offset;
|
||||
}
|
||||
|
||||
static ut32 parse_cpu_version(const char *cpu) {
|
||||
if (!cpu || !*cpu) {
|
||||
return 0;
|
||||
@@ -87,6 +101,24 @@ static bool load_string_tables(HermesArchSession *hs, RArchSession *s) {
|
||||
}
|
||||
hs->bytecode_version = hh.version;
|
||||
|
||||
const u32 function_count = hbc_function_count (hs->hbc);
|
||||
hs->function_frames = R_NEWS0 (HermesFunctionFrame, function_count);
|
||||
if (function_count && !hs->function_frames) {
|
||||
return false;
|
||||
}
|
||||
for (u32 i = 0; i < function_count; i++) {
|
||||
HBCFunc fi = { 0 };
|
||||
u32 frame_size = 0;
|
||||
if (hbc_get_function_info (hs->hbc, i, &fi).code == RESULT_SUCCESS && fi.size &&
|
||||
hbc_get_function_frame_size (hs->hbc, i, &frame_size).code == RESULT_SUCCESS) {
|
||||
HermesFunctionFrame *frame = &hs->function_frames[hs->function_frame_count++];
|
||||
frame->offset = fi.offset;
|
||||
frame->size = fi.size;
|
||||
frame->frame_size = frame_size;
|
||||
}
|
||||
}
|
||||
qsort (hs->function_frames, hs->function_frame_count, sizeof (HermesFunctionFrame), function_frame_cmp);
|
||||
|
||||
/* Get string count */
|
||||
hs->string_count = hbc_string_count (hs->hbc);
|
||||
|
||||
@@ -127,7 +159,94 @@ static bool opcode_is_conditional(u8 opcode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void parse_operands_and_set_ptr(RAnalOp *op, const ut8 *bytes, ut32 size, ut8 opcode, HermesArchSession *hs) {
|
||||
/* Return the register-frame size for the function containing addr. The cached
|
||||
* intervals are sorted by bytecode offset, so this stays logarithmic even for
|
||||
* large React Native bundles with thousands of functions. */
|
||||
static bool function_frame_size(HermesArchSession *hs, ut64 addr, ut32 *frame_size) {
|
||||
if (!hs || !hs->function_frames || !frame_size) {
|
||||
return false;
|
||||
}
|
||||
const ut64 file_addr = addr >= HBC_VADDR_BASE? addr - HBC_VADDR_BASE: addr;
|
||||
u32 lo = 0;
|
||||
u32 hi = hs->function_frame_count;
|
||||
while (lo < hi) {
|
||||
const u32 mid = lo + (hi - lo) / 2;
|
||||
if ((ut64)hs->function_frames[mid].offset <= file_addr) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
if (!lo) {
|
||||
return false;
|
||||
}
|
||||
/* Multiple deduplicated function-table entries may share the body. */
|
||||
const u32 candidate_offset = hs->function_frames[lo - 1].offset;
|
||||
u32 candidate_frame_size = 0;
|
||||
for (u32 i = lo; i > 0; i--) {
|
||||
const HermesFunctionFrame *frame = &hs->function_frames[i - 1];
|
||||
if (frame->offset != candidate_offset) {
|
||||
break;
|
||||
}
|
||||
if (file_addr < (ut64)frame->offset + frame->size) {
|
||||
candidate_frame_size = R_MAX (candidate_frame_size, frame->frame_size);
|
||||
}
|
||||
}
|
||||
*frame_size = candidate_frame_size;
|
||||
return candidate_frame_size > 0;
|
||||
}
|
||||
|
||||
static bool implicit_call_arg_count(ut8 opcode, const ut32 values[6], ut32 *argc) {
|
||||
switch (opcode) {
|
||||
case OP_Call:
|
||||
case OP_CallLong:
|
||||
case OP_Construct:
|
||||
case OP_ConstructLong:
|
||||
*argc = values[2];
|
||||
return true;
|
||||
case OP_CallDirect:
|
||||
case OP_CallDirectLongIndex:
|
||||
*argc = values[1];
|
||||
return true;
|
||||
case OP_CallBuiltin:
|
||||
case OP_CallBuiltinLong:
|
||||
*argc = values[2];
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append the implicit call-frame window after the encoded operands. Hermes
|
||||
* counts `this` in argc and stores it plus source arguments immediately below
|
||||
* the six reserved frame-header registers. */
|
||||
static void append_call_args(PJ *pj, HermesArchSession *hs, ut64 addr, ut8 opcode, const ut32 values[6]) {
|
||||
ut32 argc = 0;
|
||||
ut32 frame_size = 0;
|
||||
if (!pj || !implicit_call_arg_count (opcode, values, &argc) || !argc ||
|
||||
!function_frame_size (hs, addr, &frame_size)) {
|
||||
return;
|
||||
}
|
||||
const st64 base = (st64)frame_size - 1 - HBC_CALL_FRAME_RESERVED;
|
||||
if (base < 0 || argc > (ut32) (base + 1)) {
|
||||
return;
|
||||
}
|
||||
for (ut32 i = 0; i < argc; i++) {
|
||||
char reg[16];
|
||||
snprintf (reg, sizeof (reg), "r%" PFMT64d, base - i);
|
||||
pj_o (pj);
|
||||
pj_ks (pj, "type", "reg");
|
||||
pj_ks (pj, "value", reg);
|
||||
pj_kb (pj, "implicit", true);
|
||||
pj_ks (pj, "kind", i? "call_arg": "call_this");
|
||||
if (i) {
|
||||
pj_kn (pj, "index", i - 1);
|
||||
}
|
||||
pj_end (pj);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_operands(RAnalOp *op, const ut8 *bytes, ut32 size, ut8 opcode, ut8 canonical_opcode, HermesArchSession *hs, RArchDecodeMask mask) {
|
||||
HBCISA isa = hbc_isa_getv (hs->bytecode_version);
|
||||
const Instruction *inst_set = isa.instructions;
|
||||
if (!inst_set || opcode >= isa.count) {
|
||||
@@ -135,91 +254,211 @@ static void parse_operands_and_set_ptr(RAnalOp *op, const ut8 *bytes, ut32 size,
|
||||
}
|
||||
|
||||
const Instruction *inst = &inst_set[opcode];
|
||||
PJ *pj = NULL;
|
||||
if (mask & R_ARCH_OP_MASK_OPEX) {
|
||||
pj = pj_new ();
|
||||
if (pj) {
|
||||
pj_o (pj);
|
||||
pj_ka (pj, "operands");
|
||||
}
|
||||
}
|
||||
|
||||
// Parse operands
|
||||
ut32 operand_values[6] = { 0 };
|
||||
size_t pos = 1; // Skip opcode byte
|
||||
size_t pos = 1; /* Skip opcode byte */
|
||||
ut32 values[6] = { 0 };
|
||||
|
||||
for (int i = 0; i < 6 && inst->operands[i].operand_type != OPERAND_TYPE_NONE; i++) {
|
||||
if (pos >= size) {
|
||||
break;
|
||||
}
|
||||
|
||||
const InstructionOperand *operand = &inst->operands[i];
|
||||
ut32 value = 0;
|
||||
double double_value = 0.0;
|
||||
bool valid = false;
|
||||
switch (inst->operands[i].operand_type) {
|
||||
case OPERAND_TYPE_REG8:
|
||||
case OPERAND_TYPE_UINT8:
|
||||
case OPERAND_TYPE_ADDR8:
|
||||
if (pos < size) {
|
||||
operand_values[i] = bytes[pos];
|
||||
if (pos + 1 <= size) {
|
||||
value = bytes[pos];
|
||||
pos += 1;
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case OPERAND_TYPE_UINT16:
|
||||
if (pos + 1 < size) {
|
||||
operand_values[i] = (bytes[pos + 1] << 8) | bytes[pos];
|
||||
if (pos + 2 <= size) {
|
||||
value = r_read_le16 (bytes + pos);
|
||||
pos += 2;
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case OPERAND_TYPE_REG32:
|
||||
case OPERAND_TYPE_UINT32:
|
||||
case OPERAND_TYPE_ADDR32:
|
||||
case OPERAND_TYPE_IMM32:
|
||||
if (pos + 3 < size) {
|
||||
operand_values[i] = (bytes[pos + 3] << 24) | (bytes[pos + 2] << 16) |
|
||||
(bytes[pos + 1] << 8) | bytes[pos];
|
||||
if (pos + 4 <= size) {
|
||||
value = r_read_le32 (bytes + pos);
|
||||
pos += 4;
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case OPERAND_TYPE_DOUBLE:
|
||||
/* Double is 8 bytes - just advance position, value not used for ptr setting */
|
||||
if (pos + 7 < size) {
|
||||
if (pos + 8 <= size) {
|
||||
ut64 bits = r_read_le64 (bytes + pos);
|
||||
memcpy (&double_value, &bits, sizeof (double_value));
|
||||
pos += 8;
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case OPERAND_TYPE_NONE:
|
||||
default:
|
||||
/* OPERAND_TYPE_NONE is never reached due to loop condition */
|
||||
break;
|
||||
}
|
||||
if (!valid) {
|
||||
break;
|
||||
}
|
||||
values[i] = value;
|
||||
|
||||
// Check if this operand is a string ID
|
||||
if (inst->operands[i].operand_meaning == OPERAND_MEANING_STRING_ID) {
|
||||
ut32 string_id = operand_values[i];
|
||||
ut64 ref_addr = UT64_MAX;
|
||||
ut64 string_byte_length = UT64_MAX;
|
||||
/* Resolve IDs without replacing their raw values in OPEX. */
|
||||
if (operand->operand_meaning == OPERAND_MEANING_STRING_ID) {
|
||||
ut32 string_id = value;
|
||||
if (string_id < hs->string_count && hs->hbc) {
|
||||
HBCStringMeta meta;
|
||||
Result meta_result = hbc_get_string_meta (hs->hbc, string_id, &meta);
|
||||
if (meta_result.code == RESULT_SUCCESS) {
|
||||
op->ptr = (st64) (HBC_VADDR_BASE + meta.offset);
|
||||
ref_addr = HBC_VADDR_BASE + meta.offset;
|
||||
op->ptr = (st64)ref_addr;
|
||||
string_byte_length = meta.isUTF16? (ut64)meta.length * 2: meta.length;
|
||||
/* Expose the string byte length (size of the pointed
|
||||
* contents) so the disassembler caps r2's string read and
|
||||
* picks the right flag among overlapping, non-null-terminated
|
||||
* Hermes strings that share this storage offset. */
|
||||
op->ptrsize = meta.isUTF16? (int) (meta.length * 2): (int)meta.length;
|
||||
op->ptrsize = (int)string_byte_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if this operand is a function ID
|
||||
else if (inst->operands[i].operand_meaning == OPERAND_MEANING_FUNCTION_ID) {
|
||||
ut32 function_id = operand_values[i];
|
||||
} else if (operand->operand_meaning == OPERAND_MEANING_FUNCTION_ID) {
|
||||
ut32 function_id = value;
|
||||
if (hs->hbc) {
|
||||
ut32 offset = 0;
|
||||
HBCFunc fi;
|
||||
Result func_result = hbc_get_function_info (hs->hbc, function_id, &fi);
|
||||
if (func_result.code == RESULT_SUCCESS) {
|
||||
// name = fi.name;
|
||||
offset = fi.offset;
|
||||
(void)fi.size;
|
||||
(void)fi.param_count;
|
||||
op->ptr = (st64) (HBC_VADDR_BASE + offset);
|
||||
ref_addr = HBC_VADDR_BASE + fi.offset;
|
||||
op->ptr = (st64)ref_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pj) {
|
||||
pj_o (pj);
|
||||
if (operand->operand_type == OPERAND_TYPE_REG8 || operand->operand_type == OPERAND_TYPE_REG32) {
|
||||
char reg[16];
|
||||
snprintf (reg, sizeof (reg), "r%u", value);
|
||||
pj_ks (pj, "type", "reg");
|
||||
pj_ks (pj, "value", reg);
|
||||
} else {
|
||||
pj_ks (pj, "type", "imm");
|
||||
if (operand->operand_type == OPERAND_TYPE_DOUBLE) {
|
||||
pj_kd (pj, "value", double_value);
|
||||
} else if (operand->operand_meaning != OPERAND_MEANING_NONE) {
|
||||
pj_kn (pj, "value", value);
|
||||
} else if (operand->operand_type == OPERAND_TYPE_ADDR8) {
|
||||
pj_kN (pj, "value", (st8)value);
|
||||
} else if (operand->operand_type == OPERAND_TYPE_ADDR32 || operand->operand_type == OPERAND_TYPE_IMM32) {
|
||||
pj_kN (pj, "value", (st32)value);
|
||||
} else {
|
||||
pj_kn (pj, "value", value);
|
||||
}
|
||||
}
|
||||
if (operand->operand_meaning != OPERAND_MEANING_NONE) {
|
||||
pj_ks (pj, "kind", hbc_operand_name (operand));
|
||||
}
|
||||
if (ref_addr != UT64_MAX) {
|
||||
pj_kn (pj, "address", ref_addr);
|
||||
}
|
||||
if (string_byte_length != UT64_MAX) {
|
||||
/* Unlike RAnalOp.ptrsize, OPEX can represent a known empty
|
||||
* string without conflating its zero length with "unset". */
|
||||
pj_kn (pj, "byte_length", string_byte_length);
|
||||
}
|
||||
pj_end (pj);
|
||||
}
|
||||
}
|
||||
|
||||
if (pj) {
|
||||
append_call_args (pj, hs, op->addr, canonical_opcode, values);
|
||||
pj_end (pj); /* operands */
|
||||
pj_end (pj);
|
||||
r_strbuf_set (&op->opex, pj_string (pj));
|
||||
pj_free (pj);
|
||||
}
|
||||
}
|
||||
|
||||
/* SwitchImm stores instruction-relative deltas in a 4-byte aligned table
|
||||
* outside the instruction stream. Publish the decoded cases through the
|
||||
* standard switch_op interface so r2 analysis and external decompilers receive
|
||||
* the same control-flow facts as libhbc's built-in decompiler. */
|
||||
static bool decode_switch_op(RArchSession *s, RAnalOp *op) {
|
||||
if (!s || !s->arch || !op || !op->bytes || op->size < 18) {
|
||||
return false;
|
||||
}
|
||||
const ut32 table_delta = r_read_le32 (op->bytes + 2);
|
||||
const st32 default_delta = (st32)r_read_le32 (op->bytes + 6);
|
||||
const st32 min_val = (st32)r_read_le32 (op->bytes + 10);
|
||||
const st32 max_val = (st32)r_read_le32 (op->bytes + 14);
|
||||
const st64 amount64 = (st64)max_val - min_val + 1;
|
||||
if (amount64 <= 0 || amount64 > UT16_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ut32 amount = (ut32)amount64;
|
||||
const ut64 unaligned_table = op->addr + table_delta;
|
||||
if (unaligned_table < op->addr) {
|
||||
return false;
|
||||
}
|
||||
const ut64 table_addr = R_ROUND (unaligned_table, 4);
|
||||
const ut64 default_target = op->addr + default_delta;
|
||||
RBin *bin = s->arch->binb.bin;
|
||||
if (!bin || !bin->iob.read_at) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int table_size = (int)amount * 4;
|
||||
ut8 *table = malloc (table_size);
|
||||
if (!table) {
|
||||
return false;
|
||||
}
|
||||
if (!bin->iob.read_at (bin->iob.io, table_addr, table, table_size)) {
|
||||
free (table);
|
||||
return false;
|
||||
}
|
||||
|
||||
op->switch_op = r_anal_switch_op_new (op->addr, (ut64) (st64)min_val, (ut64) (st64)max_val, default_target);
|
||||
if (!op->switch_op) {
|
||||
free (table);
|
||||
return false;
|
||||
}
|
||||
#if R2_ABIVERSION >= 33
|
||||
op->switch_op->daddr = table_addr;
|
||||
op->switch_op->dsize = 4;
|
||||
op->switch_op->amount = amount;
|
||||
#endif
|
||||
for (ut32 i = 0; i < amount; i++) {
|
||||
const st32 delta = (st32)r_read_le32 (table + i * 4);
|
||||
const ut64 target = op->addr + delta;
|
||||
if (target != default_target) {
|
||||
r_anal_switch_op_add_case (op->switch_op, table_addr + i * 4, (ut64) (st64)min_val + i, target);
|
||||
}
|
||||
}
|
||||
free (table);
|
||||
op->fail = default_target;
|
||||
op->eob = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool decode(RArchSession *s, RAnalOp *op, RArchDecodeMask mask) {
|
||||
R_RETURN_VAL_IF_FAIL (s && op, false);
|
||||
(void)mask;
|
||||
|
||||
if (!op->bytes) {
|
||||
return false;
|
||||
@@ -283,8 +522,8 @@ static bool decode(RArchSession *s, RAnalOp *op, RArchDecodeMask mask) {
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
op->family = R_ANAL_OP_FAMILY_CPU;
|
||||
|
||||
/* Parse operands and set ptr for string/function references */
|
||||
parse_operands_and_set_ptr (op, op->bytes, op->size, sinfo.opcode, hs);
|
||||
/* Parse structured operands and set ptr for string/function references. */
|
||||
parse_operands (op, op->bytes, op->size, sinfo.opcode, sinfo.canonical_opcode, hs, mask);
|
||||
|
||||
if (mask & R_ARCH_OP_MASK_ESIL && sinfo.text) {
|
||||
set_esil (op, op->bytes, op->addr);
|
||||
@@ -510,6 +749,7 @@ static bool decode(RArchSession *s, RAnalOp *op, RArchDecodeMask mask) {
|
||||
/* Switch operations */
|
||||
case OP_SwitchImm:
|
||||
op->type = R_ANAL_OP_TYPE_SWITCH;
|
||||
decode_switch_op (s, op);
|
||||
break;
|
||||
/* Special operations */
|
||||
case OP_Unreachable:
|
||||
@@ -642,6 +882,8 @@ static bool fini(RArchSession *s) {
|
||||
}
|
||||
HermesArchSession *hs = (HermesArchSession *)s->data;
|
||||
if (hs) {
|
||||
R_FREE (hs->function_frames);
|
||||
hs->function_frame_count = 0;
|
||||
if (hs->hbc) {
|
||||
hbc_close (hs->hbc);
|
||||
hs->hbc = NULL;
|
||||
@@ -652,6 +894,48 @@ static bool fini(RArchSession *s) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* LoadParam reads a Hermes call-frame slot, not an architectural register.
|
||||
* Keep the slot index as an ESIL operand and use a custom value-producing op
|
||||
* so register-access analysis never invents arg0/arg1/... register names.
|
||||
* Concrete emulation cannot recover the caller-owned frame value here; zero is
|
||||
* the conventional unknown placeholder, while OPEX retains the exact slot. */
|
||||
static bool esil_hbc_load_param(REsil *esil) {
|
||||
R_RETURN_VAL_IF_FAIL (esil, false);
|
||||
#if R2_ABIVERSION >= 87
|
||||
const RStrs slot = r_esil_pop (esil);
|
||||
if (r_strs_empty (slot)) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
char *slot = r_esil_pop (esil);
|
||||
if (!slot) {
|
||||
return false;
|
||||
}
|
||||
free (slot);
|
||||
#endif
|
||||
return r_esil_pushnum (esil, 0);
|
||||
}
|
||||
|
||||
#if R2_ABIVERSION >= 109
|
||||
static bool esilcb(RArchSession *s R_UNUSED, REsil *esil, RArchEsilAction action) {
|
||||
#else
|
||||
static bool esilcb(RArchSession *s, RArchEsilAction action) {
|
||||
REsil *esil = s && s->arch? s->arch->esil: NULL;
|
||||
#endif
|
||||
if (!esil) {
|
||||
return false;
|
||||
}
|
||||
switch (action) {
|
||||
case R_ARCH_ESIL_ACTION_INIT:
|
||||
return r_esil_set_op (esil, "HBC_LOAD_PARAM", esil_hbc_load_param,
|
||||
1, 1, R_ESIL_OP_TYPE_CUSTOM, NULL);
|
||||
case R_ARCH_ESIL_ACTION_FINI:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register profile for ESIL emulation */
|
||||
static char *regs(RArchSession *s) {
|
||||
(void)s;
|
||||
@@ -660,14 +944,8 @@ static char *regs(RArchSession *s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Define special registers */
|
||||
/* Hermes frame arguments and VM registers have no fixed ABI homes. */
|
||||
r_strbuf_append (sb, "=PC\tpc\n");
|
||||
r_strbuf_append (sb, "=SP\tr0\n");
|
||||
r_strbuf_append (sb, "=BP\tr1\n");
|
||||
r_strbuf_append (sb, "=A0\tr2\n");
|
||||
r_strbuf_append (sb, "=A1\tr3\n");
|
||||
r_strbuf_append (sb, "=A2\tr4\n");
|
||||
r_strbuf_append (sb, "=A3\tr5\n");
|
||||
|
||||
/* Program counter - 64 bits at offset 0 */
|
||||
r_strbuf_append (sb, "gpr\tpc\t.64\t0\t0\n");
|
||||
@@ -697,6 +975,7 @@ const RArchPlugin r_arch_plugin_r2hermes = {
|
||||
.regs = regs,
|
||||
.info = archinfo,
|
||||
.mnemonics = mnemonics,
|
||||
.esilcb = esilcb,
|
||||
.init = init,
|
||||
.fini = fini,
|
||||
};
|
||||
|
||||
+126
-3
@@ -11,6 +11,10 @@
|
||||
|
||||
typedef struct {
|
||||
HBC *hbc;
|
||||
#if R2_ABIVERSION >= 142
|
||||
RVecRBinTrycatch trycatch;
|
||||
bool trycatch_loaded;
|
||||
#endif
|
||||
} HBCBinObj;
|
||||
|
||||
static bool check(RBinFile *bf, RBuffer *b) {
|
||||
@@ -29,6 +33,9 @@ static bool load(RBinFile *bf, RBuffer *buf, ut64 R_UNUSED loadaddr) {
|
||||
if (hbc_open_from_buffer (buf, &hbc).code == RESULT_SUCCESS) {
|
||||
HBCBinObj *bo = R_NEW0 (HBCBinObj);
|
||||
bo->hbc = hbc;
|
||||
#if R2_ABIVERSION >= 142
|
||||
RVecRBinTrycatch_init (&bo->trycatch);
|
||||
#endif
|
||||
bf->bo->bin_obj = bo;
|
||||
bf->buf = buf;
|
||||
return true;
|
||||
@@ -40,6 +47,9 @@ static bool load(RBinFile *bf, RBuffer *buf, ut64 R_UNUSED loadaddr) {
|
||||
static void destroy(RBinFile *bf) {
|
||||
HBCBinObj *bo = bf->bo->bin_obj;
|
||||
if (bo) {
|
||||
#if R2_ABIVERSION >= 142
|
||||
RVecRBinTrycatch_fini (&bo->trycatch);
|
||||
#endif
|
||||
hbc_safe_close (&bo->hbc);
|
||||
free (bo);
|
||||
}
|
||||
@@ -239,10 +249,110 @@ static RList *entries(RBinFile *bf) {
|
||||
return entries;
|
||||
}
|
||||
|
||||
#if R2_ABIVERSION >= 142
|
||||
static RVecRBinTrycatch *trycatch(RBinFile *bf) {
|
||||
HBCBinObj *bo = R_UNWRAP3 (bf, bo, bin_obj);
|
||||
if (!bo || bo->trycatch_loaded) {
|
||||
return bo? &bo->trycatch: NULL;
|
||||
}
|
||||
|
||||
HBC *hbc = bo->hbc;
|
||||
if (!hbc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const u32 function_count = hbc_function_count (hbc);
|
||||
for (u32 function_id = 0; function_id < function_count; function_id++) {
|
||||
HBCFunc function;
|
||||
if (hbc_get_function_info (hbc, function_id, &function).code != RESULT_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
HBCExceptionHandlerArray handlers = { 0 };
|
||||
if (hbc_get_function_exception_handlers (hbc, function_id, &handlers).code != RESULT_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
const ut64 source = HBC_VADDR_BASE + function.offset;
|
||||
for (u32 i = 0; i < handlers.count; i++) {
|
||||
const HBCExceptionHandler *handler = &handlers.handlers[i];
|
||||
if (handler->start >= handler->end || handler->end > function.size || handler->target >= function.size) {
|
||||
continue;
|
||||
}
|
||||
(void)r_bin_trycatch_add (&bo->trycatch,
|
||||
source,
|
||||
source + handler->start,
|
||||
source + handler->end,
|
||||
source + handler->target,
|
||||
0);
|
||||
}
|
||||
hbc_free_exception_handlers (&handlers);
|
||||
}
|
||||
bo->trycatch_loaded = true;
|
||||
return &bo->trycatch;
|
||||
}
|
||||
#elif R2_ABIVERSION >= 14
|
||||
static RList *trycatch(RBinFile *bf) {
|
||||
RList *ret = r_list_newf ((RListFree)r_bin_trycatch_free);
|
||||
HBC *hbc = get_hbc (bf);
|
||||
if (!ret || !hbc) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const u32 function_count = hbc_function_count (hbc);
|
||||
for (u32 function_id = 0; function_id < function_count; function_id++) {
|
||||
HBCFunc function;
|
||||
if (hbc_get_function_info (hbc, function_id, &function).code != RESULT_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
HBCExceptionHandlerArray handlers = { 0 };
|
||||
if (hbc_get_function_exception_handlers (hbc, function_id, &handlers).code != RESULT_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
const ut64 source = HBC_VADDR_BASE + function.offset;
|
||||
for (u32 i = 0; i < handlers.count; i++) {
|
||||
const HBCExceptionHandler *handler = &handlers.handlers[i];
|
||||
if (handler->start >= handler->end || handler->end > function.size || handler->target >= function.size) {
|
||||
continue;
|
||||
}
|
||||
RBinTrycatch *tc = r_bin_trycatch_new (source,
|
||||
source + handler->start,
|
||||
source + handler->end,
|
||||
source + handler->target,
|
||||
0);
|
||||
if (tc) {
|
||||
r_list_append (ret, tc);
|
||||
}
|
||||
}
|
||||
hbc_free_exception_handlers (&handlers);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ut64 baddr(RBinFile *bf R_UNUSED) {
|
||||
return HBC_VADDR_BASE;
|
||||
}
|
||||
|
||||
static void set_symbol_size(RBinSymbol *symbol, ut32 size) {
|
||||
#if R2_ABIVERSION >= 134
|
||||
symbol->attr.size = size;
|
||||
#else
|
||||
symbol->size = size;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_function_signature(RBinSymbol *symbol, const HBCFunc *func) {
|
||||
#if R2_ABIVERSION >= 100
|
||||
/* LoadParam indexes the Hermes frame arguments; they are not registers. */
|
||||
if (func->param_count <= UT16_MAX) {
|
||||
symbol->cc_arg_count = func->param_count;
|
||||
}
|
||||
symbol->ret_count = 1;
|
||||
#else
|
||||
(void)symbol;
|
||||
(void)func;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void append_binding_symbols(RList *symbols, HBC *hbc) {
|
||||
HBCBindings bindings = { 0 };
|
||||
if (hbc_scan_bindings (hbc, &bindings).code != RESULT_SUCCESS) {
|
||||
@@ -259,7 +369,7 @@ static void append_binding_symbols(RList *symbols, HBC *hbc) {
|
||||
r_bin_name_filtered (sym->name, nm);
|
||||
sym->paddr = b->offset;
|
||||
sym->vaddr = HBC_VADDR_BASE + b->offset;
|
||||
sym->size = 1;
|
||||
set_symbol_size (sym, 1);
|
||||
sym->ordinal = b->string_id;
|
||||
sym->type = R_BIN_TYPE_OBJECT_STR;
|
||||
sym->bind = R_BIN_BIND_GLOBAL_STR;
|
||||
@@ -313,7 +423,16 @@ static RList *symbols(RBinFile *bf) {
|
||||
|
||||
symbol->paddr = fi.offset;
|
||||
symbol->vaddr = HBC_VADDR_BASE + fi.offset;
|
||||
symbol->size = fi.size;
|
||||
set_symbol_size (symbol, fi.size);
|
||||
set_function_signature (symbol, &fi);
|
||||
#if R2_ABIVERSION >= 139
|
||||
if (fi.flags & HBC_FUNCTION_ASYNC) {
|
||||
symbol->attr.flags |= R_BIN_ATTR_ASYNC;
|
||||
}
|
||||
if (fi.flags & HBC_FUNCTION_GENERATOR) {
|
||||
symbol->attr.flags |= R_BIN_ATTR_GENERATOR;
|
||||
}
|
||||
#endif
|
||||
symbol->ordinal = i;
|
||||
symbol->type = R_BIN_TYPE_FUNC_STR;
|
||||
symbol->bits = 32;
|
||||
@@ -342,7 +461,7 @@ static RList *symbols(RBinFile *bf) {
|
||||
r_bin_name_filtered (sym->name, nm);
|
||||
sym->paddr = groups[i].paddr;
|
||||
sym->vaddr = HBC_VADDR_BASE + groups[i].paddr;
|
||||
sym->size = 1;
|
||||
set_symbol_size (sym, 1);
|
||||
sym->type = R_BIN_TYPE_OBJECT_STR;
|
||||
sym->bits = 32;
|
||||
r_list_append (symbols, sym);
|
||||
@@ -503,6 +622,7 @@ static RList *strings_list(RBinFile *bf) {
|
||||
ptr->vaddr = HBC_VADDR_BASE + meta.offset;
|
||||
ptr->size = meta.isUTF16? (meta.length * 2): meta.length;
|
||||
ptr->length = meta.length;
|
||||
ptr->type = meta.isUTF16? R_STRING_TYPE_WIDE: R_STRING_TYPE_UTF8;
|
||||
ptr->ordinal = i;
|
||||
r_list_append (ret, ptr);
|
||||
}
|
||||
@@ -983,6 +1103,9 @@ const RBinPlugin r_bin_plugin_r2hermes = {
|
||||
.baddr = &baddr,
|
||||
.libs = &libs,
|
||||
.lines = &lines,
|
||||
#if R2_ABIVERSION >= 14
|
||||
.trycatch = &trycatch,
|
||||
#endif
|
||||
.header = &header,
|
||||
.fields = &fields,
|
||||
#if R2_ABIVERSION >= 121
|
||||
|
||||
+159
-40
@@ -741,7 +741,8 @@ static void register_r2_artifacts(RCore *core, const HBCLiteralEntry *e) {
|
||||
if (!e->paddr) {
|
||||
return;
|
||||
}
|
||||
ut64 vaddr = HBC_VADDR_BASE + (ut64)e->paddr;
|
||||
ut64 base = r_config_get_b (core->config, "io.va")? HBC_VADDR_BASE: 0;
|
||||
ut64 vaddr = base + e->paddr;
|
||||
char flag_name[64];
|
||||
snprintf (flag_name, sizeof (flag_name), "%s0x%x", lit_kind_prefix (e->kind), e->paddr);
|
||||
r_flag_set (core->flags, flag_name, vaddr, 1);
|
||||
@@ -749,7 +750,7 @@ static void register_r2_artifacts(RCore *core, const HBCLiteralEntry *e) {
|
||||
r_meta_set_string (core->anal, R_META_TYPE_COMMENT, vaddr, e->formatted);
|
||||
}
|
||||
for (u32 i = 0; i < e->xref_count; i++) {
|
||||
ut64 from = HBC_VADDR_BASE + (ut64)e->xref_addrs[i];
|
||||
ut64 from = base + e->xref_addrs[i];
|
||||
r_anal_xrefs_set (core->anal, from, vaddr, R_ANAL_REF_TYPE_DATA);
|
||||
}
|
||||
}
|
||||
@@ -812,9 +813,10 @@ static void cmd_lit_list_quiet(HbcContext *ctx, RCore *core) {
|
||||
if (r.code != RESULT_SUCCESS) {
|
||||
R_LOG_ERROR ("%s", safe_errmsg (r.error_message));
|
||||
} else {
|
||||
ut64 base = r_config_get_b (core->config, "io.va")? HBC_VADDR_BASE: 0;
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
const HBCLiteralEntry *e = &arr[i];
|
||||
const ut64 addr = (ut64)HBC_VADDR_BASE + e->paddr;
|
||||
const ut64 addr = base + e->paddr;
|
||||
const char *fmt = e->formatted? e->formatted: "";
|
||||
r_cons_printf (core->cons, "0x%" PFMT64x " %s\n", addr, fmt);
|
||||
}
|
||||
@@ -845,18 +847,16 @@ static void cmd_lit_list_xrefs(HbcContext *ctx, RCore *core, const char *args) {
|
||||
ut64 want = r_num_get (core->num, args);
|
||||
ut64 base = va? (ut64)HBC_VADDR_BASE: 0;
|
||||
ut64 target_paddr = (want >= base)? (want - base): want;
|
||||
const HBCLiteralEntry *match = NULL;
|
||||
bool found = false;
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
if (arr[i].paddr == target_paddr) {
|
||||
match = &arr[i];
|
||||
break;
|
||||
print_xref_line (core, &arr[i], va);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
if (!found) {
|
||||
R_LOG_ERROR ("no literal at that address");
|
||||
return;
|
||||
}
|
||||
print_xref_line (core, match, va);
|
||||
return;
|
||||
}
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
@@ -904,19 +904,23 @@ static void cmd_lit_list(HbcContext *ctx, RCore *core, bool as_json) {
|
||||
}
|
||||
r_cons_printf (core->cons, "literals: %u\n", n);
|
||||
bool va = r_config_get_b (core->config, "io.va");
|
||||
ut64 base = va? HBC_VADDR_BASE: 0;
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
const HBCLiteralEntry *e = &arr[i];
|
||||
const char *pavastr = va? "vaddr": "paddr";
|
||||
r_cons_printf (core->cons,
|
||||
"%-6s n=%-4u id=(%u,%u) %s=0x%08" PFMT64x " xrefs=%u %s\n",
|
||||
"%-6s n=%-4u id=(%u,%u) %s=0x%08" PFMT64x " xrefs=%u",
|
||||
kind_label (e->kind),
|
||||
e->num_items,
|
||||
e->primary_id,
|
||||
e->secondary_id,
|
||||
pavastr,
|
||||
(ut64)HBC_VADDR_BASE + e->paddr,
|
||||
e->xref_count,
|
||||
e->formatted? e->formatted: "");
|
||||
base + e->paddr,
|
||||
e->xref_count);
|
||||
for (u32 j = 0; j < e->xref_count; j++) {
|
||||
r_cons_printf (core->cons, " 0x%" PFMT64x, base + e->xref_addrs[j]);
|
||||
}
|
||||
r_cons_printf (core->cons, " %s\n", e->formatted? e->formatted: "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -957,18 +961,16 @@ static void print_r2_for_entry(RCore *core, const HBCLiteralEntry *e, bool va) {
|
||||
r_cons_printf (core->cons, "f %s0x%x 1 @ 0x%" PFMT64x "\n", prefix, e->paddr, vaddr);
|
||||
/* embed the formatted text as a comment at the literal vaddr */
|
||||
if (e->formatted && *e->formatted) {
|
||||
char *clean = r_str_sanitize_r2 (e->formatted);
|
||||
if (clean) {
|
||||
r_str_replace_char (clean, '\n', ' ');
|
||||
r_str_replace_char (clean, '\r', ' ');
|
||||
r_cons_printf (core->cons, "\" /* %s */ CC %s @ 0x%" PFMT64x "\n", prefix, clean, vaddr);
|
||||
free (clean);
|
||||
char *b64 = r_base64_encode_dyn ((const ut8 *)e->formatted, -1);
|
||||
if (b64) {
|
||||
r_cons_printf (core->cons, "CCu base64:%s @ 0x%" PFMT64x "\n", b64, vaddr);
|
||||
free (b64);
|
||||
}
|
||||
}
|
||||
/* xref from each call site to the literal */
|
||||
for (u32 j = 0; j < e->xref_count; j++) {
|
||||
ut64 from = base + (ut64)e->xref_addrs[j];
|
||||
r_cons_printf (core->cons, "axd 0x%" PFMT64x " 0x%" PFMT64x "\n", from, vaddr);
|
||||
r_cons_printf (core->cons, "axd 0x%" PFMT64x " 0x%" PFMT64x "\n", vaddr, from);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -990,18 +992,16 @@ static void cmd_lit_print_r2(HbcContext *ctx, RCore *core, const char *args) {
|
||||
ut64 want = r_num_get (core->num, args);
|
||||
ut64 base = va? (ut64)HBC_VADDR_BASE: 0;
|
||||
ut64 target_paddr = (want >= base)? (want - base): want;
|
||||
const HBCLiteralEntry *match = NULL;
|
||||
bool found = false;
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
if (arr[i].paddr == target_paddr) {
|
||||
match = &arr[i];
|
||||
break;
|
||||
print_r2_for_entry (core, &arr[i], va);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
if (!found) {
|
||||
R_LOG_ERROR ("no literal at that address");
|
||||
return;
|
||||
}
|
||||
print_r2_for_entry (core, match, va);
|
||||
return;
|
||||
}
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
@@ -1058,29 +1058,33 @@ static void cmd_lit_toggle_inline(RCore *core) {
|
||||
/* Show help */
|
||||
static const char r2hermes_helpmsg[] =
|
||||
"Usage: r2hermes-L[subcmd]\n"
|
||||
" r2hermes-L List cached literals (auto-scans code if cache is empty)\n"
|
||||
" r2hermes-L List cached literals and constructor addresses (auto-scans if empty)\n"
|
||||
" r2hermes-Lj List as JSON (auto-scans if needed)\n"
|
||||
" r2hermes-Lq List as `<vaddr> <formatted>` per line (one per literal)\n"
|
||||
" r2hermes-Lx [addr] List as `<vaddr> <xref1> <xref2> ...` (one per literal)\n"
|
||||
" With addr: print xrefs for that single literal only\n"
|
||||
" r2hermes-Lq List as `<addr> <formatted>` per line (addresses use io.va)\n"
|
||||
" r2hermes-Lx [addr] List as `<addr> <xref1> <xref2> ...` (addresses use io.va)\n"
|
||||
" With addr: print all literals sharing that pool address\n"
|
||||
" r2hermes-Lp[ao] Scan SLP pool (default: arrays; a=arrays, o=objects)\n"
|
||||
" r2hermes-LR Reset literal cache (does not remove r2 flags/comments)\n"
|
||||
" r2hermes-Lr [addr] Print r2 oneliners (f/CC/axd) to register flag+comment+xrefs\n"
|
||||
" With addr: print oneliners for that single literal only\n"
|
||||
" With addr: print all literals sharing that pool address\n"
|
||||
" r2hermes-Lg <k> <n> <primary> [<sec>]\n"
|
||||
" Format a literal from raw params (k=a|o)\n"
|
||||
" r2hermes-Li Toggle inline literal comments in disasm\n"
|
||||
" r2hermes-L? This help\n"
|
||||
"\nDeprecated alias: pd:hL[subcmd]\n";
|
||||
" r2hermes-L? This help\n";
|
||||
|
||||
static void r2hermes_help(RCore *core) {
|
||||
const char msg[] =
|
||||
"Usage: r2hermes[-arg] # see also pd:h for decompilation\n"
|
||||
"r2hermes-h - help message (same as r2hermes-?, see pd:h? too)\n"
|
||||
"r2hermes-A - Import symbols and entrypoints\n"
|
||||
"r2hermes-AA - Also import strings and SLP literal comments/xrefs\n"
|
||||
"r2hermes-AAA - Also analyze bytecode references\n"
|
||||
"r2hermes-AAAA - Also perform full analysis (aaa)\n"
|
||||
"r2hermes-E[jq] - List direct eval instruction sites (j=JSON, q=addresses only)\n"
|
||||
"r2hermes-H - Show file information and hash status\n"
|
||||
"r2hermes-L[?] - SLP literal cache: list/scan/reset/format/toggle\n"
|
||||
"r2hermes-S[jr?] - emit SBOM from SLP literals (j=CycloneDX JSON, r=raw input)\n";
|
||||
"r2hermes-S[jr?] - emit SBOM from SLP literals (j=CycloneDX JSON, r=raw input)\n"
|
||||
"r2hermes-V[j?] - Show bytecode and React Native versions (HBC or libhermes.so)\n";
|
||||
r_cons_print (core->cons, msg);
|
||||
}
|
||||
|
||||
@@ -1098,7 +1102,6 @@ static void cmd_help(RCore *core) {
|
||||
" pd:ho [id] - Decompile with offsets (addresses) per statement\n"
|
||||
" pd:hoa - Decompile all with offsets\n"
|
||||
" pd:hs [id] - List source-line information\n"
|
||||
" pd:hL[?] - Deprecated alias for r2hermes-L[?]\n"
|
||||
" pd:h? - Show this help\n"
|
||||
"\nNote: r2 comments (CC command) are automatically inlined in decompiler output.\n");
|
||||
}
|
||||
@@ -1148,11 +1151,127 @@ static void cmd_literals(HbcContext *ctx, RCore *core, const char *arg) {
|
||||
}
|
||||
|
||||
#include "sbom.inc.c"
|
||||
#include "version.inc.c"
|
||||
|
||||
static void analysis_xref(RCore *core, ut64 from, ut64 target, RAnalRefType type, bool va) {
|
||||
if (target == UT64_MAX || target < HBC_VADDR_BASE) {
|
||||
return;
|
||||
}
|
||||
if (!va) {
|
||||
target -= HBC_VADDR_BASE;
|
||||
}
|
||||
if (r_io_is_valid_offset (core->io, target, 0)) {
|
||||
r_anal_xrefs_set (core->anal, from, target, type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode complete functions, including tails shorter than the maximum opcode
|
||||
* size that the generic aar scan skips. Decode at vaddrs so absolute function
|
||||
* and string operands from the architecture plugin share one address space. */
|
||||
static void analyze_function_refs(RCore *core, HBC *hbc, u32 id, bool va) {
|
||||
HBCFunc fi;
|
||||
const u8 *code = NULL;
|
||||
u32 size = 0;
|
||||
if (hbc_get_function_info (hbc, id, &fi).code != RESULT_SUCCESS ||
|
||||
hbc_get_function_bytecode (hbc, id, &code, &size).code != RESULT_SUCCESS || !code) {
|
||||
return;
|
||||
}
|
||||
for (u32 pc = 0; pc < size && !r_cons_is_breaked (core->cons);) {
|
||||
const ut64 vaddr = HBC_VADDR_BASE + fi.offset + pc;
|
||||
const ut64 from = va? vaddr: (ut64)fi.offset + pc;
|
||||
RAnalOp op = { 0 };
|
||||
const int len = r_anal_op (core->anal, &op, vaddr, code + pc, R_MIN (size - pc, INT_MAX), R_ARCH_OP_MASK_BASIC);
|
||||
if (len < 1 || (u32)len > size - pc) {
|
||||
r_anal_op_fini (&op);
|
||||
break;
|
||||
}
|
||||
analysis_xref (core, from, op.ptr, R_ANAL_REF_TYPE_DATA, va);
|
||||
if (op.type == R_ANAL_OP_TYPE_CALL || op.type == R_ANAL_OP_TYPE_CCALL) {
|
||||
analysis_xref (core, from, op.jump, R_ANAL_REF_TYPE_CALL, va);
|
||||
} else if (op.type == R_ANAL_OP_TYPE_JMP || op.type == R_ANAL_OP_TYPE_CJMP) {
|
||||
analysis_xref (core, from, op.jump, R_ANAL_REF_TYPE_CODE, va);
|
||||
}
|
||||
r_anal_op_fini (&op);
|
||||
pc += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_analyze(RCore *core, HbcContext *ctx, const char *arg) {
|
||||
unsigned level = 0;
|
||||
while (arg[level] == 'A') {
|
||||
level++;
|
||||
}
|
||||
const char *rest = r_str_trim_head_ro (arg + level);
|
||||
if (!strcmp (rest, "?")) {
|
||||
r_cons_print (core->cons,
|
||||
"Usage: r2hermes-A[AAA]\n"
|
||||
" r2hermes-A Import symbols and entrypoints\n"
|
||||
" r2hermes-AA Also import strings and SLP literal flags/comments/xrefs\n"
|
||||
" r2hermes-AAA Also analyze references in every bytecode function\n"
|
||||
" r2hermes-AAAA Also perform full analysis (aaa)\n"
|
||||
"Levels are cumulative; addresses follow io.va.\n");
|
||||
return;
|
||||
}
|
||||
if (level > 4 || *rest) {
|
||||
R_LOG_ERROR ("Invalid analysis level. Use r2hermes-A? for help");
|
||||
return;
|
||||
}
|
||||
HBC *hbc = NULL;
|
||||
Result res = ensure_hbc_loaded (ctx, core, &hbc);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
R_LOG_ERROR ("%s", safe_errmsg (res.error_message));
|
||||
return;
|
||||
}
|
||||
const ut64 addr = core->addr;
|
||||
const bool va = r_config_get_b (core->config, "io.va");
|
||||
if (!r_flag_space_push (core->flags, R_FLAGS_FS_SYMBOLS)) {
|
||||
return;
|
||||
}
|
||||
if (!r_core_bin_info (core, R_CORE_BIN_ACC_ENTRIES, NULL, R_MODE_SET, va, NULL, NULL) ||
|
||||
r_core_cmd0 (core, ".is*") != 0) {
|
||||
R_LOG_ERROR ("Failed to import HBC symbols and entrypoints");
|
||||
goto done;
|
||||
}
|
||||
if (level >= 2) {
|
||||
if (!r_core_bin_info (core, R_CORE_BIN_ACC_STRINGS, NULL, R_MODE_SET, va, NULL, NULL)) {
|
||||
R_LOG_ERROR ("Failed to import HBC strings");
|
||||
goto done;
|
||||
}
|
||||
res = hbc_literals_scan_code (hbc, NULL);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
R_LOG_ERROR ("Literal scan failed: %s", safe_errmsg (res.error_message));
|
||||
goto done;
|
||||
}
|
||||
r_flag_space_set (core->flags, R_FLAGS_FS_SYMBOLS);
|
||||
register_all_artifacts (core, hbc);
|
||||
}
|
||||
if (level >= 3) {
|
||||
const u32 count = hbc_function_count (hbc);
|
||||
r_cons_break_push (core->cons, NULL, NULL);
|
||||
for (u32 i = 0; i < count && !r_cons_is_breaked (core->cons); i++) {
|
||||
analyze_function_refs (core, hbc, i, va);
|
||||
}
|
||||
const bool interrupted = r_cons_is_breaked (core->cons);
|
||||
r_cons_break_pop (core->cons);
|
||||
if (interrupted) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (level >= 4) {
|
||||
r_core_cmd0 (core, "aaa");
|
||||
}
|
||||
done:
|
||||
r_flag_space_pop (core->flags);
|
||||
r_core_seek (core, addr, true);
|
||||
}
|
||||
|
||||
static void cmd_r2hermes(RCore *core, HbcContext *ctx, const char *arg) {
|
||||
arg = r_str_trim_head_ro (arg);
|
||||
if (*arg == '-') {
|
||||
switch (arg[1]) {
|
||||
case 'A':
|
||||
cmd_analyze (core, ctx, arg + 1);
|
||||
break;
|
||||
case 'E':
|
||||
cmd_list_eval_functions (ctx, core, arg + 2);
|
||||
break;
|
||||
@@ -1165,6 +1284,9 @@ static void cmd_r2hermes(RCore *core, HbcContext *ctx, const char *arg) {
|
||||
case 'S':
|
||||
cmd_sbom (ctx, core, arg + 2);
|
||||
break;
|
||||
case 'V':
|
||||
cmd_version (ctx, core, arg + 2);
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
r2hermes_help (core);
|
||||
@@ -1222,10 +1344,6 @@ static void cmd_pdh(RCore *core, HbcContext *ctx, const char *arg) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'L': /* pd:hL* — deprecated alias for r2hermes-L* */
|
||||
R_LOG_WARN ("pd:hL is deprecated; use r2hermes-L instead");
|
||||
cmd_literals (ctx, core, arg + 1);
|
||||
break;
|
||||
case 's': /* pd:hs [id] */
|
||||
cmd_source_lines (ctx, core, arg + 1);
|
||||
break;
|
||||
@@ -1394,6 +1512,7 @@ R_API RLibStruct radare_plugin = {
|
||||
.type = R_LIB_TYPE_CORE,
|
||||
.data = (void *)&r_core_plugin_r2hermes,
|
||||
.version = R2_VERSION,
|
||||
.abiversion = R2_ABIVERSION
|
||||
.abiversion = R2_ABIVERSION,
|
||||
.pkgname = "r2hermes"
|
||||
};
|
||||
#endif
|
||||
@@ -3,16 +3,23 @@
|
||||
/* Core HBC plugin with plugin registration enabled for r2one */
|
||||
|
||||
#define HBC_CORE_REGISTER_PLUGINS 1
|
||||
// radare2 defines R2_PLUGIN_INCORE when linking us statically (XPS)
|
||||
#ifdef R2_PLUGIN_INCORE
|
||||
#define HBC_STATIC_INCORE 1
|
||||
#else
|
||||
#define R2_PLUGIN_INCORE 1
|
||||
#endif
|
||||
#include "asm_hbc.c"
|
||||
#include "bin_hbc.c"
|
||||
#include "arch_hbc.c"
|
||||
#undef HBC_VADDR_BASE
|
||||
#include "core_hbc.c"
|
||||
|
||||
#ifndef HBC_STATIC_INCORE
|
||||
R_API RLibStruct radare_plugin = {
|
||||
.type = R_LIB_TYPE_CORE,
|
||||
.data = (void *)&r_core_plugin_r2hermes,
|
||||
.version = R2_VERSION,
|
||||
.abiversion = R2_ABIVERSION
|
||||
};
|
||||
#endif
|
||||
+13
-13
@@ -84,9 +84,9 @@ static void set_esil(RAnalOp *op, const u8 *bytes, ut64 addr) {
|
||||
case OP_RShift: E3 (">>")
|
||||
case OP_URshift: E3 ("0x1f,&,>>")
|
||||
case OP_Eq:
|
||||
case OP_StrictEq: E3 ("==")
|
||||
case OP_StrictEq: E3 ("==,$z")
|
||||
case OP_Neq:
|
||||
case OP_StrictNeq: E3 ("==,!")
|
||||
case OP_StrictNeq: E3 ("==,$z,!")
|
||||
case OP_Less: E3 ("<")
|
||||
case OP_Greater: E3 (">")
|
||||
case OP_LessEq: E3 ("<=")
|
||||
@@ -184,10 +184,10 @@ static void set_esil(RAnalOp *op, const u8 *bytes, ut64 addr) {
|
||||
r_strbuf_setf (&op->esil, "%u,r%u,=", r_read_le32 (bytes + 2), bytes[1]);
|
||||
break;
|
||||
case OP_LoadParam:
|
||||
r_strbuf_setf (&op->esil, "arg%u,r%u,=", bytes[2], bytes[1]);
|
||||
r_strbuf_setf (&op->esil, "%u,HBC_LOAD_PARAM,r%u,=", bytes[2], bytes[1]);
|
||||
break;
|
||||
case OP_LoadParamLong:
|
||||
r_strbuf_setf (&op->esil, "arg%u,r%u,=", r_read_le32 (bytes + 2), bytes[1]);
|
||||
r_strbuf_setf (&op->esil, "%u,HBC_LOAD_PARAM,r%u,=", r_read_le32 (bytes + 2), bytes[1]);
|
||||
break;
|
||||
case OP_NewArray:
|
||||
r_strbuf_setf (&op->esil, "%u,NEWARR,r%u,=", r_read_le16 (bytes + 2), bytes[1]);
|
||||
@@ -229,7 +229,7 @@ static void set_esil(RAnalOp *op, const u8 *bytes, ut64 addr) {
|
||||
r_strbuf_setf (&op->esil, "r%u,THROW", bytes[1]);
|
||||
break;
|
||||
case OP_ThrowIfUndefinedInst:
|
||||
r_strbuf_setf (&op->esil, "r%u,UNDEFINED,==,?{,THROW,}", bytes[1]);
|
||||
r_strbuf_setf (&op->esil, "r%u,UNDEFINED,==,$z,?{,THROW,}", bytes[1]);
|
||||
break;
|
||||
case OP_IteratorClose:
|
||||
r_strbuf_setf (&op->esil, "r%u,ITERCLOSE", bytes[1]);
|
||||
@@ -276,14 +276,14 @@ static void set_esil(RAnalOp *op, const u8 *bytes, ut64 addr) {
|
||||
case OP_JNotGreaterEqualN: JCC_S ("<")
|
||||
case OP_JNotGreaterEqualLong:
|
||||
case OP_JNotGreaterEqualNLong: JCC_L ("<")
|
||||
case OP_JEqual: JCC_S ("==")
|
||||
case OP_JEqualLong: JCC_L ("==")
|
||||
case OP_JNotEqual: JCC_S ("==,!")
|
||||
case OP_JNotEqualLong: JCC_L ("==,!")
|
||||
case OP_JStrictEqual: JCC_S ("==")
|
||||
case OP_JStrictEqualLong: JCC_L ("==")
|
||||
case OP_JStrictNotEqual: JCC_S ("==,!")
|
||||
case OP_JStrictNotEqualLong: JCC_L ("==,!")
|
||||
case OP_JEqual: JCC_S ("==,$z")
|
||||
case OP_JEqualLong: JCC_L ("==,$z")
|
||||
case OP_JNotEqual: JCC_S ("==,$z,!")
|
||||
case OP_JNotEqualLong: JCC_L ("==,$z,!")
|
||||
case OP_JStrictEqual: JCC_S ("==,$z")
|
||||
case OP_JStrictEqualLong: JCC_L ("==,$z")
|
||||
case OP_JStrictNotEqual: JCC_S ("==,$z,!")
|
||||
case OP_JStrictNotEqualLong: JCC_L ("==,$z,!")
|
||||
|
||||
/* aggregate / opaque ops with no precise ESIL model */
|
||||
case OP_Unreachable:
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/* r2hermes - BSD - Copyright 2026 - pancake */
|
||||
|
||||
/* r2hermes-V: identify the Hermes / React Native build of the loaded binary.
|
||||
*
|
||||
* For HBC files the bytecode version comes from the header. For the native
|
||||
* engine (libhermes.so) it recovers:
|
||||
* - the "for RN x.y.z" string Hermes reports as "OSS Release Version"
|
||||
* - the constant returned by HermesRuntime::getBytecodeVersion ()
|
||||
* - the toolchain recorded in .comment (via RBinInfo.compiler)
|
||||
*/
|
||||
|
||||
#include <hbc/parser.h>
|
||||
|
||||
#define HERMES_RN_TAG "for RN "
|
||||
#define HERMES_BCVER_SYM "_ZN8facebook6hermes13HermesRuntime18getBytecodeVersionEv"
|
||||
|
||||
static char *version_find_rn(RBinFile *bf) {
|
||||
ut64 size = 0;
|
||||
const ut8 *data = r_buf_data (bf->buf, &size);
|
||||
if (!data || size > ST32_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
const int taglen = strlen (HERMES_RN_TAG);
|
||||
const ut8 *p = data;
|
||||
const ut8 *end = data + size;
|
||||
while ((p = r_mem_mem (p, (int) (end - p), (const ut8 *)HERMES_RN_TAG, taglen))) {
|
||||
const ut8 *v = p + taglen;
|
||||
const ut8 *q = v;
|
||||
while (q < end && (isdigit (*q) || *q == '.' || *q == '-' || isalpha (*q))) {
|
||||
q++;
|
||||
}
|
||||
// must be a standalone NUL-terminated string starting with a digit
|
||||
if (q > v && q < end && !*q && isdigit (*v) && (p == data || !p[-1])) {
|
||||
return r_str_ndup ((const char *)v, (int) (q - v));
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int version_find_bcver(RCore *core) {
|
||||
RVecRBinSymbol *syms = r_bin_get_symbols_vec (core->bin);
|
||||
if (!syms) {
|
||||
return -1;
|
||||
}
|
||||
ut64 addr = UT64_MAX;
|
||||
RBinSymbol *sym;
|
||||
R_VEC_FOREACH (syms, sym) {
|
||||
if (sym->name && sym->vaddr && r_str_startswith (r_str_get (sym->name->oname), HERMES_BCVER_SYM)) {
|
||||
addr = sym->vaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (addr == UT64_MAX) {
|
||||
return -1;
|
||||
}
|
||||
ut8 buf[64];
|
||||
if (!r_io_read_at (core->io, addr, buf, sizeof (buf))) {
|
||||
return -1;
|
||||
}
|
||||
// the function just returns a constant; accept a short prologue before it
|
||||
int ver = -1;
|
||||
int off = 0;
|
||||
int i;
|
||||
for (i = 0; i < 8 && off < (int)sizeof (buf); i++) {
|
||||
RAnalOp op;
|
||||
r_anal_op_init (&op);
|
||||
int len = r_anal_op (core->anal, &op, addr + off, buf + off, sizeof (buf) - off, R_ARCH_OP_MASK_VAL);
|
||||
const ut32 type = op.type & R_ANAL_OP_TYPE_MASK;
|
||||
if (type == R_ANAL_OP_TYPE_MOV && op.val != UT64_MAX && op.val > 0 && op.val < 1000) {
|
||||
ver = (int)op.val;
|
||||
}
|
||||
r_anal_op_fini (&op);
|
||||
if (len < 1 || type == R_ANAL_OP_TYPE_RET) {
|
||||
break;
|
||||
}
|
||||
off += len;
|
||||
}
|
||||
return ver;
|
||||
}
|
||||
|
||||
static void cmd_version(HbcContext *ctx, RCore *core, const char *arg) {
|
||||
const bool json = *arg == 'j';
|
||||
if (*arg && !json) {
|
||||
r_cons_print (core->cons,
|
||||
"Usage: r2hermes-V[j]\n"
|
||||
" r2hermes-V Show Hermes bytecode and React Native versions\n"
|
||||
" r2hermes-Vj Same as JSON\n");
|
||||
return;
|
||||
}
|
||||
RBinFile *bf = core->bin->cur;
|
||||
if (!bf || !bf->buf) {
|
||||
R_LOG_ERROR ("No binary loaded");
|
||||
return;
|
||||
}
|
||||
int bcver = -1;
|
||||
char *rn = NULL;
|
||||
const char *compiler = NULL;
|
||||
const char *kind = "native";
|
||||
HBCHeader header;
|
||||
ut8 magic[8];
|
||||
if (r_buf_read_at (bf->buf, 0, magic, sizeof (magic)) == sizeof (magic) && r_read_le64 (magic) == HEADER_MAGIC && hbc_load_current_binary (ctx, core).code == RESULT_SUCCESS && hbc_get_header (ctx->hbc, &header).code == RESULT_SUCCESS) {
|
||||
kind = "hbc";
|
||||
bcver = header.version;
|
||||
} else {
|
||||
rn = version_find_rn (bf);
|
||||
bcver = version_find_bcver (core);
|
||||
RBinInfo *info = r_bin_get_info (core->bin);
|
||||
compiler = info? info->compiler: NULL;
|
||||
if (!rn && bcver < 0) {
|
||||
R_LOG_WARN ("This does not look like a Hermes binary");
|
||||
}
|
||||
}
|
||||
RCons *cons = core->cons;
|
||||
if (json) {
|
||||
PJ *pj = r_core_pj_new (core);
|
||||
pj_o (pj);
|
||||
pj_ks (pj, "type", kind);
|
||||
if (bcver >= 0) {
|
||||
pj_kn (pj, "bytecode_version", bcver);
|
||||
}
|
||||
if (rn) {
|
||||
pj_ks (pj, "react_native", rn);
|
||||
}
|
||||
if (compiler) {
|
||||
pj_ks (pj, "compiler", compiler);
|
||||
}
|
||||
pj_end (pj);
|
||||
char *s = pj_drain (pj);
|
||||
r_cons_println (cons, s);
|
||||
free (s);
|
||||
} else {
|
||||
r_cons_printf (cons, "type %s\n", kind);
|
||||
if (bcver >= 0) {
|
||||
r_cons_printf (cons, "bytecode_version %d\n", bcver);
|
||||
}
|
||||
if (rn) {
|
||||
r_cons_printf (cons, "react_native %s\n", rn);
|
||||
}
|
||||
if (compiler) {
|
||||
r_cons_printf (cons, "compiler %s\n", compiler);
|
||||
}
|
||||
}
|
||||
free (rn);
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
NAME=r2hermes analysis help
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
r2hermes-?~r2hermes-A
|
||||
r2hermes-A?
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
r2hermes-A - Import symbols and entrypoints
|
||||
r2hermes-AA - Also import strings and SLP literal comments/xrefs
|
||||
r2hermes-AAA - Also analyze bytecode references
|
||||
r2hermes-AAAA - Also perform full analysis (aaa)
|
||||
Usage: r2hermes-A[AAA]
|
||||
r2hermes-A Import symbols and entrypoints
|
||||
r2hermes-AA Also import strings and SLP literal flags/comments/xrefs
|
||||
r2hermes-AAA Also analyze references in every bytecode function
|
||||
r2hermes-AAAA Also perform full analysis (aaa)
|
||||
Levels are cumulative; addresses follow io.va.
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-A imports symbols and preserves session state
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
f-*
|
||||
fs scratch
|
||||
s 0x100000b4
|
||||
r2hermes-A
|
||||
?v $$
|
||||
fs~scratch[1]
|
||||
fs *
|
||||
f~global,entry,str.
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x100000b4
|
||||
*
|
||||
0x100000b0 1 entry0
|
||||
0x100000b0 10 sym.global_0x000000b0
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-AA adds strings
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
f-*
|
||||
r2hermes-AA
|
||||
f~global,entry,str.
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x1000009c 6 str.global
|
||||
0x100000a2 11 str.print_123__
|
||||
0x100000b0 1 entry0
|
||||
0x100000b0 10 sym.global_0x000000b0
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-AA imports literals again from an existing cache
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
r2hermes-Lq~^0x10037b28
|
||||
ax-*
|
||||
f- lit.*
|
||||
CC- @ 0x10037b28
|
||||
r2hermes-AA
|
||||
f~lit.obj.0x37b28
|
||||
CC. @ 0x10037b28
|
||||
axtq @ 0x10037b28
|
||||
r2hermes-AA
|
||||
axtq @ 0x10037b28
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x10037b28 {trace: 0, info: 1, warn: 2, error: 3}
|
||||
0x10037b28 1 lit.obj.0x37b28
|
||||
{trace: 0, info: 1, warn: 2, error: 3}
|
||||
0x1003e9f9
|
||||
0x1003e9f9
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-AA imports literal physical addresses
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
ARGS=-e io.va=false
|
||||
CMDS=<<EOF
|
||||
f-*
|
||||
r2hermes-AA
|
||||
f~lit.obj.0x37b28
|
||||
CC. @ 0x37b28
|
||||
axtq @ 0x37b28
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x00037b28 1 lit.obj.0x37b28
|
||||
{trace: 0, info: 1, warn: 2, error: 3}
|
||||
0x3e9f9
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-AAA finds short function references and remains additive
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
ax-*
|
||||
r2hermes-AA
|
||||
axtq @ 0x100000a2
|
||||
r2hermes-AAA
|
||||
axtq @ 0x100000a2
|
||||
r2hermes-AAA
|
||||
axtq @ 0x100000a2
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x100000b0
|
||||
0x100000b0
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-AAA uses physical addresses for code and data
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e io.va=false
|
||||
CMDS=<<EOF
|
||||
ax-*
|
||||
r2hermes-AAA
|
||||
axtq @ 0xa2
|
||||
axtq @ 0x100000a2
|
||||
f~global,entry,str.print
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0xb0
|
||||
0x0000009c 6 str.global
|
||||
0x000000a2 11 str.print_123__
|
||||
0x000000b0 1 entry0
|
||||
0x000000b0 10 sym.global_0x000000b0
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-AAAA analyzes function control flow
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e log.level=0
|
||||
CMDS=<<EOF
|
||||
r2hermes-AAAA
|
||||
aflj~{[0].addr}
|
||||
aflj~{[0].size}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
268435632
|
||||
10
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes analysis rejects invalid levels before importing
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
f-*
|
||||
r2hermes-AAAAA
|
||||
r2hermes-AAj
|
||||
r2hermes-AA extra
|
||||
f
|
||||
EOF
|
||||
EXPECT=
|
||||
EXPECT_ERR=<<EOF
|
||||
ERROR: Invalid analysis level. Use r2hermes-A? for help
|
||||
ERROR: Invalid analysis level. Use r2hermes-A? for help
|
||||
ERROR: Invalid analysis level. Use r2hermes-A? for help
|
||||
EOF
|
||||
RUN
|
||||
@@ -415,9 +415,7 @@ RUN
|
||||
|
||||
NAME=pd:hc short-circuit OR merges consecutive same-target conditional gotos
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
pd:hc 730~ || r2===r20 ||
|
||||
EOF
|
||||
CMDS=pd:hc 730~ \|\| r2===r20 \|\|
|
||||
EXPECT=<<EOF
|
||||
if (r1===r20 || r2===r20 || r3===r20 || r4===r20) goto loc_00055f28;
|
||||
EOF
|
||||
|
||||
@@ -84,6 +84,77 @@ EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc function signature metadata
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e asm.sub.varmin=16
|
||||
CMDS=<<EOF
|
||||
isj~{[0].arg_count}
|
||||
isj~{[0].cc_arg_count}
|
||||
isj~{[0].ret_count}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0
|
||||
1
|
||||
1
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc register profile has no fake ABI roles
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e asm.sub.varmin=16
|
||||
CMDS=<<EOF
|
||||
drpj~{alias_info}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
[{"role":0,"role_str":"PC","reg":"pc"}]
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc LoadParam ESIL uses a frame slot instead of a fake register
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
ARGS=-e asm.sub.varmin=16
|
||||
CMDS=<<EOF
|
||||
aoj 1 @ 0x1003e3f7~{[0].esil}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
1,HBC_LOAD_PARAM,r8,=
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc equality branch ESIL materializes the zero comparison
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
ARGS=-e asm.sub.varmin=16
|
||||
CMDS=<<EOF
|
||||
aoj 1 @ 0x1003e5fc~{[0].esil}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
r1,r3,==,$z,!,?{,0x1003e637,pc,=,}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc SwitchImm analysis exposes jump table metadata
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
af @ 0x1004d09a
|
||||
agfj @ 0x1004d09a~{[0].blocks[0].switchop}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
{"addr":268751010,"defval":268751197,"maxval":27,"minval":0,"daddr":268751204,"dsize":4,"amount":28,"cases":[{"addr":268751204,"value":0,"jump":268751078},{"addr":268751208,"value":1,"jump":268751028},{"addr":268751212,"value":2,"jump":268751078},{"addr":268751224,"value":5,"jump":268751172},{"addr":268751248,"value":11,"jump":268751050},{"addr":268751256,"value":13,"jump":268751124},{"addr":268751264,"value":15,"jump":268751078},{"addr":268751268,"value":16,"jump":268751148},{"addr":268751280,"value":19,"jump":268751100},{"addr":268751308,"value":26,"jump":268751172},{"addr":268751312,"value":27,"jump":268751172}]}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc exception handlers are exposed through bin metadata
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
iw*~try.0
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
f try.0.1003e6dc.from=0x1003e703
|
||||
f try.0.1003e6dc.to=0x1003e713
|
||||
f try.0.1003e6dc.catch=0x1003e715
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc entry point (va)
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e asm.sub.varmin=16
|
||||
@@ -182,6 +253,50 @@ EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc structured operands
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
aoj 3 @ entry0~{0.opex}
|
||||
aoj 3 @ entry0~{1.opex}
|
||||
aoj 3 @ entry0~{2.opex}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
{"operands":[{"type":"reg","value":"r0"},{"type":"imm","value":1,"kind":"string_id","address":268435618,"byte_length":11}]}
|
||||
{"operands":[{"type":"reg","value":"r0"},{"type":"reg","value":"r0"},{"type":"imm","value":0}]}
|
||||
{"operands":[{"type":"reg","value":"r0"}]}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc structured empty string length
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
aoj 1 @ 0x1003e45b~{0.opex}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
{"operands":[{"type":"reg","value":"r9"},{"type":"imm","value":2976,"kind":"string_id","address":268560336,"byte_length":0}]}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc structured function operand
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
aoj 1 @ 0x1003a3bb~{0.opex}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
{"operands":[{"type":"reg","value":"r1"},{"type":"reg","value":"r3"},{"type":"imm","value":1,"kind":"function_id","address":268690421}]}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc implicit call frame operands
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
aoj 1 @ 0x100895ac~{0.opex}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
{"operands":[{"type":"reg","value":"r1"},{"type":"reg","value":"r5"},{"type":"imm","value":5},{"type":"reg","value":"r10","implicit":true,"kind":"call_this"},{"type":"reg","value":"r9","implicit":true,"kind":"call_arg","index":0},{"type":"reg","value":"r8","implicit":true,"kind":"call_arg","index":1},{"type":"reg","value":"r7","implicit":true,"kind":"call_arg","index":2},{"type":"reg","value":"r6","implicit":true,"kind":"call_arg","index":3}]}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc sections (va)
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e asm.sub.varmin=16
|
||||
|
||||
@@ -81,3 +81,16 @@ EXPECT=<<EOF
|
||||
{"magic":2240826417119764422,"version":96,"sourceHash":"a97c8302dab90bec7184a9183b22b43badd57a65","fileLength":292,"globalCodeIndex":0,"functionCount":1,"stringKindCount":1,"identifierCount":0,"stringCount":2,"overflowStringCount":0,"stringStorageSize":17,"bigIntCount":0,"bigIntStorageSize":0,"regExpCount":0,"regExpStorageSize":0,"literalValueBufferSize":0,"arrayBufferSize":0,"objKeyBufferSize":0,"objValueBufferSize":0,"objShapeTableCount":0,"numStringSwitchImms":0,"segmentID":0,"cjsModuleCount":0,"functionSourceCount":0,"debugInfoOffset":200,"staticBuiltins":false,"cjsModulesStaticallyResolved":false,"hasAsync":false}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=r2hermes-V reports the HBC bytecode version
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
r2hermes-V
|
||||
r2hermes-Vj
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
type hbc
|
||||
bytecode_version 96
|
||||
{"type":"hbc","bytecode_version":96}
|
||||
EOF
|
||||
RUN
|
||||
@@ -0,0 +1,59 @@
|
||||
NAME=hbc literal addresses and constructor refs
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
r2hermes-L~trace:
|
||||
r2hermes-Lx 0x10037b3c
|
||||
r2hermes-Lr 0x10037b3c~^axd
|
||||
ax-*
|
||||
.r2hermes-Lr 0x10037b3c
|
||||
axtq @ 0x10037b3c
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
object n=4 id=(0,0) vaddr=0x10037b28 xrefs=1 0x1003e9f9 {trace: 0, info: 1, warn: 2, error: 3}
|
||||
0x10037b3c 0x1003eb09 0x1003ebe7
|
||||
0x10037b3c 0x100c2cfb
|
||||
axd 0x10037b3c 0x1003eb09
|
||||
axd 0x10037b3c 0x1003ebe7
|
||||
axd 0x10037b3c 0x100c2cfb
|
||||
0x1003eb09
|
||||
0x1003ebe7
|
||||
0x100c2cfb
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc literal physical addresses and refs
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
ARGS=-e io.va=false
|
||||
CMDS=<<EOF
|
||||
r2hermes-L~trace:
|
||||
r2hermes-Lq~^0x37b28
|
||||
r2hermes-Lx 0x37b3c
|
||||
r2hermes-Lr 0x37b3c~^axd
|
||||
axtq @ 0x37b3c
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
object n=4 id=(0,0) paddr=0x00037b28 xrefs=1 0x3e9f9 {trace: 0, info: 1, warn: 2, error: 3}
|
||||
0x37b28 {trace: 0, info: 1, warn: 2, error: 3}
|
||||
0x37b3c 0x3eb09 0x3ebe7
|
||||
0x37b3c 0xc2cfb
|
||||
axd 0x37b3c 0x3eb09
|
||||
axd 0x37b3c 0x3ebe7
|
||||
axd 0x37b3c 0xc2cfb
|
||||
0x3eb09
|
||||
0x3ebe7
|
||||
0xc2cfb
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc literal help drops deprecated alias
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
r2hermes-L?~pd:hL
|
||||
pd:h?~pd:hL
|
||||
pd:hL?
|
||||
EOF
|
||||
EXPECT=
|
||||
EXPECT_ERR=<<EOF
|
||||
ERROR: Unknown subcommand. Use pd:h? for help
|
||||
EOF
|
||||
RUN
|
||||
+124
-1
@@ -1,6 +1,7 @@
|
||||
/* r2hermes - BSD - Copyright 2025-2026 - pancake */
|
||||
|
||||
#include "../src/lib/hbc_internal.h"
|
||||
#include <hbc/opcodes.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -18,6 +19,9 @@ static int test_small_debug_info(const char *root) {
|
||||
|
||||
HBC *hbc = NULL;
|
||||
CHECK (hbc_open (path, &hbc).code == RESULT_SUCCESS);
|
||||
u32 frame_size = 0;
|
||||
CHECK (hbc_get_function_frame_size (hbc, 0, &frame_size).code == RESULT_SUCCESS);
|
||||
CHECK (frame_size == hbc->reader.function_headers[0].frameSize);
|
||||
|
||||
HBCDebugInfo di = { 0 };
|
||||
CHECK (hbc_get_debug_info (hbc, &di).code == RESULT_SUCCESS);
|
||||
@@ -74,6 +78,81 @@ static int test_empty_debug_info(const char *root) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_exception_handlers(const char *root) {
|
||||
char path[512];
|
||||
snprintf (path, sizeof (path), "%s/test/bins/hbc/index.android.bundle", root);
|
||||
|
||||
HBC *hbc = NULL;
|
||||
CHECK (hbc_open (path, &hbc).code == RESULT_SUCCESS);
|
||||
u32 handler_count = 0;
|
||||
u32 generator_count = 0;
|
||||
for (u32 function_id = 0; function_id < hbc_function_count (hbc); function_id++) {
|
||||
HBCFunc function;
|
||||
CHECK (hbc_get_function_info (hbc, function_id, &function).code == RESULT_SUCCESS);
|
||||
CHECK (!(function.flags & HBC_FUNCTION_ASYNC));
|
||||
if (function.flags & HBC_FUNCTION_GENERATOR) {
|
||||
generator_count++;
|
||||
}
|
||||
HBCExceptionHandlerArray handlers = { 0 };
|
||||
CHECK (hbc_get_function_exception_handlers (hbc, function_id, &handlers).code == RESULT_SUCCESS);
|
||||
for (u32 i = 0; i < handlers.count; i++) {
|
||||
CHECK (handlers.handlers[i].start < handlers.handlers[i].end);
|
||||
CHECK (handlers.handlers[i].end <= function.size);
|
||||
CHECK (handlers.handlers[i].target < function.size);
|
||||
}
|
||||
handler_count += handlers.count;
|
||||
hbc_free_exception_handlers (&handlers);
|
||||
}
|
||||
CHECK (handler_count > 0);
|
||||
CHECK (generator_count > 0);
|
||||
hbc_close (hbc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const Instruction *find_instruction(HBCISA isa, const char *name) {
|
||||
for (u32 i = 0; i < isa.count; i++) {
|
||||
if (isa.instructions[i].name && !strcmp (isa.instructions[i].name, name)) {
|
||||
return &isa.instructions[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int test_opcode_operand_meanings(void) {
|
||||
static const int versions[] = {
|
||||
51, 58, 59, 61, 62, 68, 69, 70, 72, 73, 76, 80, 81, 82,
|
||||
83, 84, 85, 86, 87, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99
|
||||
};
|
||||
static const char *function_ops[] = {
|
||||
"call_direct", "call_direct_long_index",
|
||||
"create_closure", "create_closure_long_index",
|
||||
"create_generator_closure", "create_generator_closure_long_index",
|
||||
"create_async_closure", "create_async_closure_long_index",
|
||||
"create_generator", "create_generator_long_index"
|
||||
};
|
||||
static const char *builtin_ops[] = {
|
||||
"call_builtin", "call_builtin_long", "get_builtin_closure",
|
||||
"jmp_builtin_is", "jmp_builtin_is_long",
|
||||
"jmp_builtin_is_not", "jmp_builtin_is_not_long"
|
||||
};
|
||||
for (size_t i = 0; i < sizeof (versions) / sizeof (versions[0]); i++) {
|
||||
HBCISA isa = hbc_isa_getv (versions[i]);
|
||||
for (size_t j = 0; j < sizeof (function_ops) / sizeof (function_ops[0]); j++) {
|
||||
const Instruction *insn = find_instruction (isa, function_ops[j]);
|
||||
if (insn) {
|
||||
CHECK (insn->operands[2].operand_meaning == OPERAND_MEANING_FUNCTION_ID);
|
||||
}
|
||||
}
|
||||
for (size_t j = 0; j < sizeof (builtin_ops) / sizeof (builtin_ops[0]); j++) {
|
||||
const Instruction *insn = find_instruction (isa, builtin_ops[j]);
|
||||
if (insn) {
|
||||
CHECK (insn->operands[1].operand_meaning == OPERAND_MEANING_BUILTIN_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_function_bytecode_bounds(const char *root) {
|
||||
char path[512];
|
||||
snprintf (path, sizeof (path), "%s/test/bins/hbc/bespoke_eval.hbc", root);
|
||||
@@ -130,9 +209,53 @@ static int test_decode_rejects_bad_overflow_string_index(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_literal_addresses(void) {
|
||||
u8 keys[] = { 0x71, 1, 0, 0, 0 };
|
||||
u8 values[] = { 0x71, 20, 0, 0, 0, 0x71, 36, 0, 0, 0 };
|
||||
ShapeTableEntry shape = { .key_buffer_offset = 0, .prop_count = 1 };
|
||||
for (u32 version = 96; version <= 97; version++) {
|
||||
HBC hbc = { 0 };
|
||||
RVecHBCLiteralEntry_init (&hbc.lit_cache.entries);
|
||||
hbc.reader.header.version = version;
|
||||
hbc.reader.header.arrayBufferSize = sizeof (values);
|
||||
hbc.reader.header.objKeyBufferSize = sizeof (keys);
|
||||
hbc.reader.header.objValueBufferSize = sizeof (values);
|
||||
hbc.reader.arrays = values;
|
||||
hbc.reader.arrays_paddr = 0x100;
|
||||
hbc.reader.object_keys = keys;
|
||||
hbc.reader.object_keys_paddr = 0x200;
|
||||
hbc.reader.object_values = values;
|
||||
hbc.reader.object_values_paddr = version >= 97? 0x100: 0x300;
|
||||
hbc.reader.object_shapes = &shape;
|
||||
hbc.reader.object_shape_count = 1;
|
||||
u32 num_items = version >= 97? 0: 1;
|
||||
CHECK (hbc_literals_register (&hbc, HBC_LIT_OBJECT, num_items, 0, 0, 0x400).code == RESULT_SUCCESS);
|
||||
CHECK (hbc_literals_register (&hbc, HBC_LIT_OBJECT, num_items, 0, 5, 0x410).code == RESULT_SUCCESS);
|
||||
CHECK (hbc_literals_register (&hbc, HBC_LIT_OBJECT, num_items, 0, 5, 0x420).code == RESULT_SUCCESS);
|
||||
CHECK (hbc_literals_register (&hbc, HBC_LIT_ARRAY, 1, 5, 0, 0x430).code == RESULT_SUCCESS);
|
||||
CHECK (hbc_literals_register (&hbc, HBC_LIT_OBJECT, num_items, 0, sizeof (values), 0x440).code == RESULT_SUCCESS);
|
||||
const HBCLiteralEntry *entries = NULL;
|
||||
u32 count = 0;
|
||||
CHECK (hbc_literals_list (&hbc, &entries, &count).code == RESULT_SUCCESS);
|
||||
CHECK (count == 4);
|
||||
CHECK (entries[0].paddr == hbc.reader.object_values_paddr);
|
||||
CHECK (entries[1].paddr == hbc.reader.object_values_paddr + 5);
|
||||
CHECK (entries[2].paddr == 0x105);
|
||||
CHECK (entries[3].paddr == 0);
|
||||
CHECK (!strcmp (entries[0].formatted, "{1: 20}"));
|
||||
CHECK (!strcmp (entries[1].formatted, "{1: 36}"));
|
||||
CHECK (!strcmp (entries[2].formatted, "[36]"));
|
||||
CHECK (entries[1].xref_count == 2);
|
||||
CHECK (entries[1].xref_addrs[0] == 0x410);
|
||||
CHECK (entries[1].xref_addrs[1] == 0x420);
|
||||
hbc_literals_reset (&hbc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *root = argc > 1? argv[1]: ".";
|
||||
if (test_small_debug_info (root) || test_empty_debug_info (root) || test_function_bytecode_bounds (root) || test_decode_rejects_bad_overflow_string_index ()) {
|
||||
if (test_small_debug_info (root) || test_empty_debug_info (root) || test_exception_handlers (root) || test_opcode_operand_meanings () || test_function_bytecode_bounds (root) || test_decode_rejects_bad_overflow_string_index () || test_literal_addresses ()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user