mirror of
https://github.com/radareorg/r2hermes.git
synced 2026-11-07 18:37:54 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d77df7091 | ||
|
|
722793f084 | ||
|
|
0b53e148fb | ||
|
|
a93ca6767d | ||
|
|
e3f5b7e560 | ||
|
|
47279d355c | ||
|
|
3b08970ce8 | ||
|
|
0566ca00a8 | ||
|
|
4bfde1f33f | ||
|
|
6a243fbc1e | ||
|
|
e073f29cb3 |
No files matched your search
@@ -4,8 +4,5 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "##build "
|
||||
prefix-development: "##build "
|
||||
labels:
|
||||
- buildsystem
|
||||
+18
-18
@@ -1,7 +1,7 @@
|
||||
name: CI
|
||||
|
||||
env:
|
||||
R2V: 6.2.2
|
||||
R2V: 6.2.6
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -19,14 +19,14 @@ 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@v3
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
- name: Build library
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v3
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
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
|
||||
@@ -86,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
|
||||
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v3
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
@@ -140,7 +140,7 @@ jobs:
|
||||
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-*.zip
|
||||
@@ -155,10 +155,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Install radare2
|
||||
uses: radareorg/github-actions@v3
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
run: make bindist
|
||||
|
||||
- name: Upload r2pm binary artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: bindist-${{ matrix.os }}
|
||||
path: r2hermes-*.zip
|
||||
@@ -180,7 +180,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -192,26 +192,26 @@ 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@v8
|
||||
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: |
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v3
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,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
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
|
||||
- name: Install radare2
|
||||
id: r2
|
||||
uses: radareorg/github-actions@v3
|
||||
uses: radareorg/github-actions@4ae27a8b29a049ac0fd5119f6eda37ecfc64ead8 # v3
|
||||
with:
|
||||
version: ${{ env.R2V }}
|
||||
|
||||
@@ -60,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/
|
||||
|
||||
@@ -119,7 +119,33 @@ user-install user-uninstall:
|
||||
$(MAKE) -C src/r2 $@
|
||||
|
||||
# Binary package for r2pm -bi: plugins/ and bin/ for this r2 version and platform
|
||||
BINDIST_ZIP=r2hermes-$(shell r2 -qv)-$(shell r2pm -H R2PM_OS)-$(shell r2pm -H R2PM_ARCH)-$(shell r2pm -H R2PM_BITS).zip
|
||||
# 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.5.2',
|
||||
version: '1.6.2',
|
||||
license: 'MIT',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
||||
@@ -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;
|
||||
|
||||
+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);
|
||||
|
||||
+153
-39
@@ -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,25 +1058,28 @@ 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"
|
||||
@@ -1099,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");
|
||||
}
|
||||
@@ -1151,10 +1153,125 @@ 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;
|
||||
@@ -1227,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;
|
||||
@@ -1399,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
|
||||
@@ -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
|
||||
@@ -146,7 +146,7 @@ RUN
|
||||
NAME=hbc exception handlers are exposed through bin metadata
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
iw~try.0
|
||||
iw*~try.0
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
f try.0.1003e6dc.from=0x1003e703
|
||||
|
||||
@@ -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
|
||||
+45
-1
@@ -209,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_exception_handlers (root) || test_opcode_operand_meanings () || 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