mirror of
https://github.com/radareorg/r2hermes.git
synced 2026-11-09 12:31:29 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9821c3f425 | ||
|
|
32d1965288 | ||
|
|
56900a5064 | ||
|
|
d6e807bc1c | ||
|
|
76ec5ad0f8 | ||
|
|
c08dcc3268 |
No files matched your search
@@ -81,7 +81,6 @@ test: $(BIN_FILE) $(TEST_BIN)
|
||||
$(BIN_FILE) sl test/bins/hbc/bespoke_eval.hbc | grep -q '0x000000b4 f=0 +0x4 yes.js:1:5 stmt=0'
|
||||
$(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) libs test/bins/hbc/index.android.bundle | grep -q 'react-native'
|
||||
|
||||
r2:
|
||||
$(MAKE) clean
|
||||
|
||||
@@ -344,22 +344,6 @@ typedef struct {
|
||||
u32 count;
|
||||
} HBCBindings;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *path;
|
||||
char *version;
|
||||
const char *kind; /* cjs, package, js, native, global */
|
||||
u32 function_id;
|
||||
u32 offset;
|
||||
u32 string_id;
|
||||
bool inferred;
|
||||
} HBCModule;
|
||||
|
||||
typedef struct {
|
||||
HBCModule *modules;
|
||||
u32 count;
|
||||
} HBCModules;
|
||||
|
||||
/**
|
||||
* Free instruction array.
|
||||
*/
|
||||
@@ -373,13 +357,6 @@ void hbc_free_insns(HBCInsn *insns, u32 count);
|
||||
Result hbc_scan_bindings(HBC *hbc, HBCBindings *out);
|
||||
void hbc_free_bindings(HBCBindings *bindings);
|
||||
|
||||
/**
|
||||
* List probable bundled modules/libraries. Hermes bytecode has no SBOM table,
|
||||
* so versions are only populated when they are explicitly preserved in strings.
|
||||
*/
|
||||
Result hbc_list_modules(HBC *hbc, HBCModules *out);
|
||||
void hbc_free_modules(HBCModules *modules);
|
||||
|
||||
/**
|
||||
* Encoding buffer and functions
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
project(
|
||||
'r2hermes',
|
||||
'c',
|
||||
version: '1.2.8',
|
||||
version: '1.2.6',
|
||||
license: 'MIT',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
||||
+50
-244
@@ -863,10 +863,12 @@ static const BindingHint g_hints[] = {
|
||||
};
|
||||
#define HINTS_N (sizeof (g_hints) / sizeof (g_hints[0]))
|
||||
|
||||
/* Per-sid dedup flags for hbc_scan_bindings; avoids O(N^2) strcmp dedup. */
|
||||
#define SEEN_CJS 0x1
|
||||
#define SEEN_IMP 0x2
|
||||
#define SEEN_EXP 0x4
|
||||
static bool str_eq(const char *a, const char *b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
return a && b && !strcmp (a, b);
|
||||
}
|
||||
|
||||
static bool is_export_marker(const char *s) {
|
||||
return !strcmp (s, "exports") || !strcmp (s, "module");
|
||||
@@ -878,6 +880,13 @@ static bool is_export_store(const char *name) {
|
||||
|
||||
static Result binding_add(HBCBindings *out, HBCBindingType type, const char *kind,
|
||||
const char *name, const char *module, u32 function_id, u32 offset, u32 string_id) {
|
||||
for (u32 i = 0; i < out->count; i++) {
|
||||
HBCBinding *b = &out->bindings[i];
|
||||
if (b->type == type && !strcmp (b->kind, kind)
|
||||
&& !strcmp (b->name, name) && str_eq (b->module, module)) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
}
|
||||
HBCBinding *nb = realloc (out->bindings, (out->count + 1) * sizeof (HBCBinding));
|
||||
if (!nb) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "OOM");
|
||||
@@ -940,11 +949,7 @@ static size_t decode_operands(const Instruction *inst, const u8 *bytes, size_t l
|
||||
return pos;
|
||||
}
|
||||
|
||||
static Result scan_hint_matches(HBCBindings *out, const char *s, u32 fid, u32 off, u32 sid, u8 *flag) {
|
||||
/* Dedup identical (kind,module) across hints (pointers are stable literals).
|
||||
* Set SEEN_EXP when adding an EXPORT so caller's put_by_id skips this sid. */
|
||||
const void *added[HINTS_N * 2];
|
||||
u32 added_n = 0;
|
||||
static Result scan_hint_matches(HBCBindings *out, const char *s, u32 fid, u32 off, u32 sid) {
|
||||
for (size_t h = 0; h < HINTS_N; h++) {
|
||||
const BindingHint *hint = &g_hints[h];
|
||||
bool match = hint->name? !strcmp (s, hint->name):
|
||||
@@ -952,27 +957,37 @@ static Result scan_hint_matches(HBCBindings *out, const char *s, u32 fid, u32 of
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
bool dup = false;
|
||||
for (u32 a = 0; a < added_n; a += 2) {
|
||||
if (added[a] == hint->kind && added[a + 1] == hint->module) {
|
||||
dup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dup) {
|
||||
continue;
|
||||
}
|
||||
added[added_n++] = hint->kind;
|
||||
added[added_n++] = hint->module;
|
||||
if (hint->type == HBC_BINDING_EXPORT) {
|
||||
*flag |= SEEN_EXP;
|
||||
}
|
||||
RETURN_IF_ERROR (binding_add (out, hint->type, hint->kind, s,
|
||||
hint->module, fid, off, sid));
|
||||
}
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
static bool function_has_export_marker(HBCReader *r, const u8 *code, u32 size, HBCISA isa) {
|
||||
for (u32 pc = 0; pc < size; ) {
|
||||
u8 op = code[pc];
|
||||
const Instruction *inst = (op < isa.count)? &isa.instructions[op]: NULL;
|
||||
if (!inst || !inst->name || !inst->binary_size) {
|
||||
break;
|
||||
}
|
||||
u32 values[6];
|
||||
if (!decode_operands (inst, code + pc, size - pc, values)) {
|
||||
break;
|
||||
}
|
||||
for (int i = 0; i < 6 && inst->operands[i].operand_type != OPERAND_TYPE_NONE; i++) {
|
||||
if (inst->operands[i].operand_meaning == OPERAND_MEANING_STRING_ID) {
|
||||
u32 sid = values[i];
|
||||
const char *s = (sid < r->header.stringCount && r->strings)? r->strings[sid]: NULL;
|
||||
if (s && is_export_marker (s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
pc += inst->binary_size;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Result hbc_scan_bindings(HBC *hbc, HBCBindings *out) {
|
||||
if (!hbc || !out) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "invalid args");
|
||||
@@ -983,29 +998,16 @@ Result hbc_scan_bindings(HBC *hbc, HBCBindings *out) {
|
||||
if (!isa.instructions) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "no isa for version");
|
||||
}
|
||||
u32 sc = r->header.stringCount;
|
||||
u8 *seen = sc? calloc (sc, 1): NULL;
|
||||
if (sc && !seen) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "OOM");
|
||||
}
|
||||
Result res = SUCCESS_RESULT ();
|
||||
if (r->header.cjsModuleCount > 0 && r->header.version >= 77 && r->cjs_modules) {
|
||||
for (u32 i = 0; i < r->header.cjsModuleCount; i++) {
|
||||
u32 sid = r->cjs_modules[i].symbol_id;
|
||||
const char *name = (sid < sc && r->strings)? r->strings[sid]: NULL;
|
||||
if (!name || !*name || (seen[sid] & SEEN_CJS)) {
|
||||
continue;
|
||||
}
|
||||
seen[sid] |= SEEN_CJS;
|
||||
res = binding_add (out, HBC_BINDING_IMPORT, "cjs", name,
|
||||
"commonjs", 0, r->cjs_modules[i].offset, sid);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
goto done;
|
||||
const char *name = (sid < r->header.stringCount && r->strings)? r->strings[sid]: NULL;
|
||||
if (name && *name) {
|
||||
RETURN_IF_ERROR (binding_add (out, HBC_BINDING_IMPORT,
|
||||
"cjs", name, "commonjs", 0, r->cjs_modules[i].offset, sid));
|
||||
}
|
||||
}
|
||||
}
|
||||
struct { u32 sid, off; } *cand = NULL;
|
||||
u32 cand_cap = 0;
|
||||
for (u32 fid = 0; fid < r->header.functionCount; fid++) {
|
||||
const u8 *code = NULL;
|
||||
u32 size = 0;
|
||||
@@ -1015,8 +1017,7 @@ Result hbc_scan_bindings(HBC *hbc, HBCBindings *out) {
|
||||
}
|
||||
HBCFunc fi = { 0 };
|
||||
(void)hbc_get_function_info (hbc, fid, &fi);
|
||||
u32 cand_n = 0;
|
||||
bool has_marker = false;
|
||||
bool has_export_marker = function_has_export_marker (r, code, size, isa);
|
||||
for (u32 pc = 0; pc < size; ) {
|
||||
u8 op = code[pc];
|
||||
const Instruction *inst = (op < isa.count)? &isa.instructions[op]: NULL;
|
||||
@@ -1027,72 +1028,25 @@ Result hbc_scan_bindings(HBC *hbc, HBCBindings *out) {
|
||||
if (!decode_operands (inst, code + pc, size - pc, values)) {
|
||||
break;
|
||||
}
|
||||
bool is_store = is_export_store (inst->name);
|
||||
for (int i = 0; i < 6 && inst->operands[i].operand_type != OPERAND_TYPE_NONE; i++) {
|
||||
if (inst->operands[i].operand_meaning != OPERAND_MEANING_STRING_ID) {
|
||||
continue;
|
||||
}
|
||||
u32 sid = values[i];
|
||||
if (sid >= sc || !r->strings) {
|
||||
continue;
|
||||
}
|
||||
const char *s = r->strings[sid];
|
||||
const char *s = (sid < r->header.stringCount && r->strings)? r->strings[sid]: NULL;
|
||||
if (!s || !*s) {
|
||||
continue;
|
||||
}
|
||||
bool marker = is_export_marker (s);
|
||||
if (marker) {
|
||||
has_marker = true;
|
||||
}
|
||||
if (!(seen[sid] & SEEN_IMP)) {
|
||||
seen[sid] |= SEEN_IMP;
|
||||
res = scan_hint_matches (out, s, fid, fi.offset + pc, sid, &seen[sid]);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
goto done_scan;
|
||||
}
|
||||
}
|
||||
if (is_store && !marker && !(seen[sid] & SEEN_EXP)) {
|
||||
if (cand_n == cand_cap) {
|
||||
u32 nc = cand_cap? cand_cap * 2: 16;
|
||||
void *nb = realloc (cand, nc * sizeof (*cand));
|
||||
if (!nb) {
|
||||
res = ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "OOM");
|
||||
goto done_scan;
|
||||
}
|
||||
cand = nb;
|
||||
cand_cap = nc;
|
||||
}
|
||||
cand[cand_n].sid = sid;
|
||||
cand[cand_n].off = fi.offset + pc;
|
||||
cand_n++;
|
||||
RETURN_IF_ERROR (scan_hint_matches (out, s, fid, fi.offset + pc, sid));
|
||||
if (has_export_marker && is_export_store (inst->name) && !is_export_marker (s)) {
|
||||
RETURN_IF_ERROR (binding_add (out, HBC_BINDING_EXPORT,
|
||||
"module", s, NULL, fid, fi.offset + pc, sid));
|
||||
}
|
||||
}
|
||||
pc += inst->binary_size;
|
||||
}
|
||||
if (!has_marker) {
|
||||
continue;
|
||||
}
|
||||
for (u32 k = 0; k < cand_n; k++) {
|
||||
u32 sid = cand[k].sid;
|
||||
if (seen[sid] & SEEN_EXP) {
|
||||
continue;
|
||||
}
|
||||
seen[sid] |= SEEN_EXP;
|
||||
res = binding_add (out, HBC_BINDING_EXPORT, "module",
|
||||
r->strings[sid], NULL, fid, cand[k].off, sid);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
goto done_scan;
|
||||
}
|
||||
}
|
||||
}
|
||||
done_scan:
|
||||
free (cand);
|
||||
done:
|
||||
free (seen);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
hbc_free_bindings (out);
|
||||
}
|
||||
return res;
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
void hbc_free_bindings(HBCBindings *bindings) {
|
||||
@@ -1108,154 +1062,6 @@ void hbc_free_bindings(HBCBindings *bindings) {
|
||||
bindings->count = 0;
|
||||
}
|
||||
|
||||
static char *dup_range(const char *s, size_t n) {
|
||||
char *ret = (char *)malloc (n + 1);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy (ret, s, n);
|
||||
ret[n] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *package_from_path(const char *s) {
|
||||
const char *nm = strstr (s, "node_modules/");
|
||||
if (nm) {
|
||||
const char *p = nm + strlen ("node_modules/");
|
||||
const char *end;
|
||||
if (*p == '@') {
|
||||
const char *scope_end = strchr (p, '/');
|
||||
if (!scope_end) {
|
||||
return strdup (p);
|
||||
}
|
||||
end = strchr (scope_end + 1, '/');
|
||||
} else {
|
||||
end = strchr (p, '/');
|
||||
}
|
||||
return end? dup_range (p, (size_t)(end - p)): strdup (p);
|
||||
}
|
||||
if (s[0] == '@') {
|
||||
const char *scope_end = strchr (s, '/');
|
||||
if (scope_end) {
|
||||
const char *end = strchr (scope_end + 1, '/');
|
||||
return end? dup_range (s, (size_t)(end - s)): strdup (s);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool module_eq(const HBCModule *m, const char *kind, const char *name) {
|
||||
return m->kind && kind && !strcmp (m->kind, kind)
|
||||
&& m->name && name && !strcmp (m->name, name);
|
||||
}
|
||||
|
||||
static Result module_add(HBCModules *out, const char *kind, const char *name,
|
||||
const char *path, const char *version, u32 function_id, u32 offset,
|
||||
u32 string_id, bool inferred) {
|
||||
if (!name || !*name) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
for (u32 i = 0; i < out->count; i++) {
|
||||
if (module_eq (&out->modules[i], kind, name)) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
}
|
||||
HBCModule *nm = realloc (out->modules, (out->count + 1) * sizeof (HBCModule));
|
||||
if (!nm) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "OOM");
|
||||
}
|
||||
out->modules = nm;
|
||||
HBCModule *m = &nm[out->count++];
|
||||
*m = (HBCModule){
|
||||
.name = strdup (name),
|
||||
.path = path? strdup (path): NULL,
|
||||
.version = version? strdup (version): NULL,
|
||||
.kind = kind,
|
||||
.function_id = function_id,
|
||||
.offset = offset,
|
||||
.string_id = string_id,
|
||||
.inferred = inferred,
|
||||
};
|
||||
if (!m->name || (path && !m->path) || (version && !m->version)) {
|
||||
return ERROR_RESULT (RESULT_ERROR_MEMORY_ALLOCATION, "OOM");
|
||||
}
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
Result hbc_list_modules(HBC *hbc, HBCModules *out) {
|
||||
if (!hbc || !out) {
|
||||
return ERROR_RESULT (RESULT_ERROR_INVALID_ARGUMENT, "invalid args");
|
||||
}
|
||||
memset (out, 0, sizeof (*out));
|
||||
HBCReader *r = &hbc->reader;
|
||||
if (r->header.cjsModuleCount > 0 && r->header.version >= 77 && r->cjs_modules) {
|
||||
for (u32 i = 0; i < r->header.cjsModuleCount; i++) {
|
||||
u32 sid = r->cjs_modules[i].symbol_id;
|
||||
const char *s = (sid < r->header.stringCount && r->strings)? r->strings[sid]: NULL;
|
||||
if (!s || !*s) {
|
||||
continue;
|
||||
}
|
||||
char *pkg = package_from_path (s);
|
||||
if (pkg) {
|
||||
Result res = module_add (out, "package", pkg, s, NULL, 0,
|
||||
r->cjs_modules[i].offset, sid, true);
|
||||
free (pkg);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
hbc_free_modules (out);
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
Result res = module_add (out, "cjs", s, s, NULL, 0,
|
||||
r->cjs_modules[i].offset, sid, false);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
hbc_free_modules (out);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HBCBindings bindings = { 0 };
|
||||
Result res = hbc_scan_bindings (hbc, &bindings);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
hbc_free_modules (out);
|
||||
return res;
|
||||
}
|
||||
for (u32 i = 0; i < bindings.count; i++) {
|
||||
HBCBinding *b = &bindings.bindings[i];
|
||||
if (b->type != HBC_BINDING_IMPORT) {
|
||||
continue;
|
||||
}
|
||||
const char *name = b->module? b->module: b->name;
|
||||
if (!name || !*name || !strcmp (name, "commonjs")) {
|
||||
name = b->name;
|
||||
}
|
||||
res = module_add (out, b->kind? b->kind: "js", name,
|
||||
b->name, NULL, b->function_id, b->offset, b->string_id, true);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
hbc_free_bindings (&bindings);
|
||||
hbc_free_modules (out);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
hbc_free_bindings (&bindings);
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
void hbc_free_modules(HBCModules *modules) {
|
||||
if (!modules || !modules->modules) {
|
||||
return;
|
||||
}
|
||||
for (u32 i = 0; i < modules->count; i++) {
|
||||
free (modules->modules[i].name);
|
||||
free (modules->modules[i].path);
|
||||
free (modules->modules[i].version);
|
||||
}
|
||||
free (modules->modules);
|
||||
modules->modules = NULL;
|
||||
modules->count = 0;
|
||||
}
|
||||
|
||||
/* Encoding functions */
|
||||
|
||||
Result hbc_enc(
|
||||
|
||||
+12
-265
@@ -220,9 +220,15 @@ static RList *sections(RBinFile *bf) {
|
||||
* literals live, and lets users `s` / `pd @` straight into them. */
|
||||
HBC *hbc = get_hbc (bf);
|
||||
if (hbc) {
|
||||
add_pool_section (sections, "slp.arrays", hbc_get_pool_paddr (hbc, HBC_LIT_ARRAY), hbc_get_pool_size (hbc, HBC_LIT_ARRAY));
|
||||
add_pool_section (sections, "slp.object_keys", hbc_get_pool_paddr (hbc, HBC_LIT_OBJECT), hbc_get_pool_size (hbc, HBC_LIT_OBJECT));
|
||||
add_pool_section (sections, "slp.object_values", hbc_get_object_values_paddr (hbc), hbc_get_object_values_size (hbc));
|
||||
add_pool_section (sections, "slp.arrays",
|
||||
hbc_get_pool_paddr (hbc, HBC_LIT_ARRAY),
|
||||
hbc_get_pool_size (hbc, HBC_LIT_ARRAY));
|
||||
add_pool_section (sections, "slp.object_keys",
|
||||
hbc_get_pool_paddr (hbc, HBC_LIT_OBJECT),
|
||||
hbc_get_pool_size (hbc, HBC_LIT_OBJECT));
|
||||
add_pool_section (sections, "slp.object_values",
|
||||
hbc_get_object_values_paddr (hbc),
|
||||
hbc_get_object_values_size (hbc));
|
||||
}
|
||||
|
||||
return sections;
|
||||
@@ -338,7 +344,8 @@ static RList *symbols(RBinFile *bf) {
|
||||
const char *prefix = k? "lit.obj.": "lit.arr.";
|
||||
HBCPoolGroup *groups = NULL;
|
||||
u32 n = 0;
|
||||
if (hbc_literals_scan_pool (hbc, kind, &groups, &n).code != RESULT_SUCCESS || !groups) {
|
||||
if (hbc_literals_scan_pool (hbc, kind, &groups, &n).code
|
||||
!= RESULT_SUCCESS || !groups) {
|
||||
continue;
|
||||
}
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
@@ -392,44 +399,13 @@ static RList *imports(RBinFile *bf) {
|
||||
return imports;
|
||||
}
|
||||
|
||||
static bool list_has_string(RList *list, const char *name) {
|
||||
RListIter *iter;
|
||||
const char *it;
|
||||
r_list_foreach (list, iter, it) {
|
||||
if (it && name && !strcmp (it, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static RList *libs(RBinFile *bf) {
|
||||
RList *libs = r_list_newf (free);
|
||||
HBC *hbc = get_hbc (bf);
|
||||
if (!libs || !hbc) {
|
||||
return libs;
|
||||
}
|
||||
HBCModules modules = { 0 };
|
||||
if (hbc_list_modules (hbc, &modules).code != RESULT_SUCCESS) {
|
||||
return libs;
|
||||
}
|
||||
for (u32 i = 0; i < modules.count; i++) {
|
||||
HBCModule *m = &modules.modules[i];
|
||||
if (m->name && *m->name && !list_has_string (libs, m->name)) {
|
||||
r_list_append (libs, strdup (m->name));
|
||||
}
|
||||
}
|
||||
hbc_free_modules (&modules);
|
||||
return libs;
|
||||
}
|
||||
|
||||
static R_UNOWNED RList *lines(RBinFile *bf) {
|
||||
HBC *hbc = get_hbc (bf);
|
||||
if (!hbc) {
|
||||
return NULL;
|
||||
}
|
||||
/* Respect bin.dbginfo=false — return early so the lazy debug-info parse
|
||||
*(triggered by hbc_get_source_lines) never runs for users who opted out. */
|
||||
* (triggered by hbc_get_source_lines) never runs for users who opted out. */
|
||||
if (bf->rbin && !bf->rbin->want_dbginfo) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -519,232 +495,6 @@ static RList *strings(RBinFile *bf) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hbc_source_hash_hex(const HBCHeader *hh, char *dst, size_t dstsz) {
|
||||
if (!dst || dstsz < 41) {
|
||||
return;
|
||||
}
|
||||
r_hex_bin2str (hh->sourceHash, 20, dst);
|
||||
}
|
||||
|
||||
static void hbc_header_print_u32(RStrBuf *sb, ut64 off, const char *name, ut32 value) {
|
||||
r_strbuf_appendf (sb, "0x%08" PFMT64x " %-29s 0x%08x\n", off, name, value);
|
||||
}
|
||||
|
||||
static void hbc_header_print_bool(RStrBuf *sb, ut64 off, const char *name, bool value) {
|
||||
r_strbuf_appendf (sb, "0x%08" PFMT64x " %-29s %s\n", off, name, value? "true": "false");
|
||||
}
|
||||
|
||||
static char *header(RBinFile *bf, int mode) {
|
||||
HBC *hbc = get_hbc (bf);
|
||||
if (!hbc) {
|
||||
return NULL;
|
||||
}
|
||||
HBCHeader hh;
|
||||
if (hbc_get_header (hbc, &hh).code != RESULT_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
char hash[41] = { 0 };
|
||||
hbc_source_hash_hex (&hh, hash, sizeof (hash));
|
||||
RStrBuf *sb = r_strbuf_new ("");
|
||||
if (!sb) {
|
||||
return NULL;
|
||||
}
|
||||
if (mode == R_MODE_EQUAL) {
|
||||
r_strbuf_appendf (sb, "magic=0x%016" PFMT64x "\n", hh.magic);
|
||||
r_strbuf_appendf (sb, "version=%u\n", hh.version);
|
||||
r_strbuf_appendf (sb, "sourceHash=%s\n", hash);
|
||||
r_strbuf_appendf (sb, "fileLength=%u\n", hh.fileLength);
|
||||
r_strbuf_appendf (sb, "globalCodeIndex=%u\n", hh.globalCodeIndex);
|
||||
r_strbuf_appendf (sb, "functionCount=%u\n", hh.functionCount);
|
||||
r_strbuf_appendf (sb, "stringKindCount=%u\n", hh.stringKindCount);
|
||||
r_strbuf_appendf (sb, "identifierCount=%u\n", hh.identifierCount);
|
||||
r_strbuf_appendf (sb, "stringCount=%u\n", hh.stringCount);
|
||||
r_strbuf_appendf (sb, "overflowStringCount=%u\n", hh.overflowStringCount);
|
||||
r_strbuf_appendf (sb, "stringStorageSize=%u\n", hh.stringStorageSize);
|
||||
r_strbuf_appendf (sb, "bigIntCount=%u\n", hh.bigIntCount);
|
||||
r_strbuf_appendf (sb, "bigIntStorageSize=%u\n", hh.bigIntStorageSize);
|
||||
r_strbuf_appendf (sb, "regExpCount=%u\n", hh.regExpCount);
|
||||
r_strbuf_appendf (sb, "regExpStorageSize=%u\n", hh.regExpStorageSize);
|
||||
r_strbuf_appendf (sb, "literalValueBufferSize=%u\n", hh.literalValueBufferSize);
|
||||
r_strbuf_appendf (sb, "arrayBufferSize=%u\n", hh.arrayBufferSize);
|
||||
r_strbuf_appendf (sb, "objKeyBufferSize=%u\n", hh.objKeyBufferSize);
|
||||
r_strbuf_appendf (sb, "objValueBufferSize=%u\n", hh.objValueBufferSize);
|
||||
r_strbuf_appendf (sb, "objShapeTableCount=%u\n", hh.objShapeTableCount);
|
||||
r_strbuf_appendf (sb, "numStringSwitchImms=%u\n", hh.numStringSwitchImms);
|
||||
r_strbuf_appendf (sb, "segmentID=%u\n", hh.segmentID);
|
||||
r_strbuf_appendf (sb, "cjsModuleCount=%u\n", hh.cjsModuleCount);
|
||||
r_strbuf_appendf (sb, "functionSourceCount=%u\n", hh.functionSourceCount);
|
||||
r_strbuf_appendf (sb, "debugInfoOffset=%u\n", hh.debugInfoOffset);
|
||||
r_strbuf_appendf (sb, "staticBuiltins=%s\n", hh.staticBuiltins? "true": "false");
|
||||
r_strbuf_appendf (sb, "cjsModulesStaticallyResolved=%s\n", hh.cjsModulesStaticallyResolved? "true": "false");
|
||||
r_strbuf_appendf (sb, "hasAsync=%s\n", hh.hasAsync? "true": "false");
|
||||
return r_strbuf_drain (sb);
|
||||
}
|
||||
if (mode == R_MODE_JSON) {
|
||||
PJ *pj = pj_new ();
|
||||
if (!pj) {
|
||||
r_strbuf_free (sb);
|
||||
return NULL;
|
||||
}
|
||||
pj_o (pj);
|
||||
pj_kn (pj, "magic", hh.magic);
|
||||
pj_kn (pj, "version", hh.version);
|
||||
pj_ks (pj, "sourceHash", hash);
|
||||
pj_kn (pj, "fileLength", hh.fileLength);
|
||||
pj_kn (pj, "globalCodeIndex", hh.globalCodeIndex);
|
||||
pj_kn (pj, "functionCount", hh.functionCount);
|
||||
pj_kn (pj, "stringKindCount", hh.stringKindCount);
|
||||
pj_kn (pj, "identifierCount", hh.identifierCount);
|
||||
pj_kn (pj, "stringCount", hh.stringCount);
|
||||
pj_kn (pj, "overflowStringCount", hh.overflowStringCount);
|
||||
pj_kn (pj, "stringStorageSize", hh.stringStorageSize);
|
||||
pj_kn (pj, "bigIntCount", hh.bigIntCount);
|
||||
pj_kn (pj, "bigIntStorageSize", hh.bigIntStorageSize);
|
||||
pj_kn (pj, "regExpCount", hh.regExpCount);
|
||||
pj_kn (pj, "regExpStorageSize", hh.regExpStorageSize);
|
||||
pj_kn (pj, "literalValueBufferSize", hh.literalValueBufferSize);
|
||||
pj_kn (pj, "arrayBufferSize", hh.arrayBufferSize);
|
||||
pj_kn (pj, "objKeyBufferSize", hh.objKeyBufferSize);
|
||||
pj_kn (pj, "objValueBufferSize", hh.objValueBufferSize);
|
||||
pj_kn (pj, "objShapeTableCount", hh.objShapeTableCount);
|
||||
pj_kn (pj, "numStringSwitchImms", hh.numStringSwitchImms);
|
||||
pj_kn (pj, "segmentID", hh.segmentID);
|
||||
pj_kn (pj, "cjsModuleCount", hh.cjsModuleCount);
|
||||
pj_kn (pj, "functionSourceCount", hh.functionSourceCount);
|
||||
pj_kn (pj, "debugInfoOffset", hh.debugInfoOffset);
|
||||
pj_kb (pj, "staticBuiltins", hh.staticBuiltins);
|
||||
pj_kb (pj, "cjsModulesStaticallyResolved", hh.cjsModulesStaticallyResolved);
|
||||
pj_kb (pj, "hasAsync", hh.hasAsync);
|
||||
pj_end (pj);
|
||||
r_strbuf_free (sb);
|
||||
return pj_drain (pj);
|
||||
}
|
||||
ut64 off = 0;
|
||||
r_strbuf_append (sb, "Hermes bytecode header:\n");
|
||||
r_strbuf_appendf (sb, "0x%08" PFMT64x " %-29s 0x%016" PFMT64x "\n", off, "magic", hh.magic);
|
||||
off += 8;
|
||||
hbc_header_print_u32 (sb, off, "version", hh.version);
|
||||
off += 4;
|
||||
r_strbuf_appendf (sb, "0x%08" PFMT64x " %-29s %s\n", off, "sourceHash", hash);
|
||||
off += 20;
|
||||
hbc_header_print_u32 (sb, off, "fileLength", hh.fileLength);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "globalCodeIndex", hh.globalCodeIndex);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "functionCount", hh.functionCount);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "stringKindCount", hh.stringKindCount);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "identifierCount", hh.identifierCount);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "stringCount", hh.stringCount);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "overflowStringCount", hh.overflowStringCount);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "stringStorageSize", hh.stringStorageSize);
|
||||
off += 4;
|
||||
if (hh.version >= 87) {
|
||||
hbc_header_print_u32 (sb, off, "bigIntCount", hh.bigIntCount);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "bigIntStorageSize", hh.bigIntStorageSize);
|
||||
off += 4;
|
||||
}
|
||||
hbc_header_print_u32 (sb, off, "regExpCount", hh.regExpCount);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "regExpStorageSize", hh.regExpStorageSize);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "literalValueBufferSize", hh.literalValueBufferSize);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "objKeyBufferSize", hh.objKeyBufferSize);
|
||||
off += 4;
|
||||
if (hh.version >= 97) {
|
||||
hbc_header_print_u32 (sb, off, "objShapeTableCount", hh.objShapeTableCount);
|
||||
off += 4;
|
||||
} else {
|
||||
hbc_header_print_u32 (sb, off, "objValueBufferSize", hh.objValueBufferSize);
|
||||
off += 4;
|
||||
}
|
||||
if (hh.version >= 99) {
|
||||
hbc_header_print_u32 (sb, off, "numStringSwitchImms", hh.numStringSwitchImms);
|
||||
off += 4;
|
||||
}
|
||||
hbc_header_print_u32 (sb, off, "segmentID", hh.segmentID);
|
||||
off += 4;
|
||||
hbc_header_print_u32 (sb, off, "cjsModuleCount", hh.cjsModuleCount);
|
||||
off += 4;
|
||||
if (hh.version >= 84) {
|
||||
hbc_header_print_u32 (sb, off, "functionSourceCount", hh.functionSourceCount);
|
||||
off += 4;
|
||||
}
|
||||
hbc_header_print_u32 (sb, off, "debugInfoOffset", hh.debugInfoOffset);
|
||||
off += 4;
|
||||
hbc_header_print_bool (sb, off, "staticBuiltins", hh.staticBuiltins);
|
||||
hbc_header_print_bool (sb, off, "cjsModulesStaticallyResolved", hh.cjsModulesStaticallyResolved);
|
||||
hbc_header_print_bool (sb, off, "hasAsync", hh.hasAsync);
|
||||
return r_strbuf_drain (sb);
|
||||
}
|
||||
|
||||
static void hbc_fields_append_u32(RList *ret, ut64 *off, const char *name, ut32 value) {
|
||||
r_list_append (ret, r_bin_field_new (*off, *off, value, 4, name, NULL, "x", false));
|
||||
*off += 4;
|
||||
}
|
||||
|
||||
static RList *fields(RBinFile *bf) {
|
||||
RList *ret = r_list_new ();
|
||||
HBC *hbc = get_hbc (bf);
|
||||
if (!ret || !hbc) {
|
||||
return ret;
|
||||
}
|
||||
HBCHeader hh;
|
||||
if (hbc_get_header (hbc, &hh).code != RESULT_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
char hash[41] = { 0 };
|
||||
hbc_source_hash_hex (&hh, hash, sizeof (hash));
|
||||
ut64 off = 0;
|
||||
r_list_append (ret, r_bin_field_new (off, off, hh.magic, 8, "magic", NULL, "q", false));
|
||||
off += 8;
|
||||
hbc_fields_append_u32 (ret, &off, "version", hh.version);
|
||||
r_list_append (ret, r_bin_field_new (off, off, 0, 20, "sourceHash", hash, "s", false));
|
||||
off += 20;
|
||||
hbc_fields_append_u32 (ret, &off, "fileLength", hh.fileLength);
|
||||
hbc_fields_append_u32 (ret, &off, "globalCodeIndex", hh.globalCodeIndex);
|
||||
hbc_fields_append_u32 (ret, &off, "functionCount", hh.functionCount);
|
||||
hbc_fields_append_u32 (ret, &off, "stringKindCount", hh.stringKindCount);
|
||||
hbc_fields_append_u32 (ret, &off, "identifierCount", hh.identifierCount);
|
||||
hbc_fields_append_u32 (ret, &off, "stringCount", hh.stringCount);
|
||||
hbc_fields_append_u32 (ret, &off, "overflowStringCount", hh.overflowStringCount);
|
||||
hbc_fields_append_u32 (ret, &off, "stringStorageSize", hh.stringStorageSize);
|
||||
if (hh.version >= 87) {
|
||||
hbc_fields_append_u32 (ret, &off, "bigIntCount", hh.bigIntCount);
|
||||
hbc_fields_append_u32 (ret, &off, "bigIntStorageSize", hh.bigIntStorageSize);
|
||||
}
|
||||
hbc_fields_append_u32 (ret, &off, "regExpCount", hh.regExpCount);
|
||||
hbc_fields_append_u32 (ret, &off, "regExpStorageSize", hh.regExpStorageSize);
|
||||
hbc_fields_append_u32 (ret, &off, "literalValueBufferSize", hh.literalValueBufferSize);
|
||||
hbc_fields_append_u32 (ret, &off, "objKeyBufferSize", hh.objKeyBufferSize);
|
||||
if (hh.version >= 97) {
|
||||
hbc_fields_append_u32 (ret, &off, "objShapeTableCount", hh.objShapeTableCount);
|
||||
} else {
|
||||
hbc_fields_append_u32 (ret, &off, "objValueBufferSize", hh.objValueBufferSize);
|
||||
}
|
||||
if (hh.version >= 99) {
|
||||
hbc_fields_append_u32 (ret, &off, "numStringSwitchImms", hh.numStringSwitchImms);
|
||||
}
|
||||
hbc_fields_append_u32 (ret, &off, "segmentID", hh.segmentID);
|
||||
hbc_fields_append_u32 (ret, &off, "cjsModuleCount", hh.cjsModuleCount);
|
||||
if (hh.version >= 84) {
|
||||
hbc_fields_append_u32 (ret, &off, "functionSourceCount", hh.functionSourceCount);
|
||||
}
|
||||
hbc_fields_append_u32 (ret, &off, "debugInfoOffset", hh.debugInfoOffset);
|
||||
ut32 flags = (hh.staticBuiltins? 1: 0) | (hh.cjsModulesStaticallyResolved? 2: 0) | (hh.hasAsync? 4: 0);
|
||||
r_list_append (ret, r_bin_field_new (off, off, flags, 1, "flags", NULL, "b", false));
|
||||
r_list_append (ret, r_bin_field_new (off, off, hh.staticBuiltins? 1: 0, 1, "staticBuiltins", NULL, "b", false));
|
||||
r_list_append (ret, r_bin_field_new (off, off, hh.cjsModulesStaticallyResolved? 1: 0, 1, "cjsModulesStaticallyResolved", NULL, "b", false));
|
||||
r_list_append (ret, r_bin_field_new (off, off, hh.hasAsync? 1: 0, 1, "hasAsync", NULL, "b", false));
|
||||
return ret;
|
||||
}
|
||||
|
||||
const RBinPlugin r_bin_plugin_r2hermes = {
|
||||
.meta = {
|
||||
.name = "hbc.bin",
|
||||
@@ -761,11 +511,8 @@ const RBinPlugin r_bin_plugin_r2hermes = {
|
||||
.baddr = &baddr,
|
||||
.symbols = &symbols,
|
||||
.imports = &imports,
|
||||
.libs = &libs,
|
||||
.lines = &lines,
|
||||
.strings = &strings,
|
||||
.header = &header,
|
||||
.fields = &fields,
|
||||
};
|
||||
|
||||
#ifndef R2_PLUGIN_INCORE
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <r_core.h>
|
||||
#include <hbc/hbc.h>
|
||||
#include <hbc/literals.h>
|
||||
#include <hbc/opcodes.h>
|
||||
#include "utils.inc.c"
|
||||
|
||||
#define HBC_VADDR_BASE 0x10000000ULL
|
||||
@@ -261,55 +260,6 @@ static void cmd_list_functions(HbcContext *ctx, RCore *core) {
|
||||
}
|
||||
}
|
||||
|
||||
/* List functions containing direct eval instructions */
|
||||
static void cmd_list_eval_functions(HbcContext *ctx, RCore *core) {
|
||||
Result res = hbc_load_current_binary (ctx, core);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
R_LOG_ERROR ("%s", safe_errmsg (res.error_message));
|
||||
return;
|
||||
}
|
||||
|
||||
HBCHeader header;
|
||||
res = hbc_get_header (ctx->hbc, &header);
|
||||
if (res.code != RESULT_SUCCESS) {
|
||||
R_LOG_ERROR ("reading header: %s", safe_errmsg (res.error_message));
|
||||
return;
|
||||
}
|
||||
HBCISA isa = hbc_isa_getv (header.version);
|
||||
if (!isa.instructions) {
|
||||
R_LOG_ERROR ("No ISA for Hermes bytecode version %u", header.version);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 count = hbc_function_count (ctx->hbc);
|
||||
for (u32 fid = 0; fid < count; fid++) {
|
||||
HBCFunc info;
|
||||
if (hbc_get_function_info (ctx->hbc, fid, &info).code != RESULT_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
const u8 *code = NULL;
|
||||
u32 size = 0;
|
||||
if (hbc_get_function_bytecode (ctx->hbc, fid, &code, &size).code != RESULT_SUCCESS || !code) {
|
||||
continue;
|
||||
}
|
||||
for (u32 pc = 0; pc < size; ) {
|
||||
const u8 op = code[pc];
|
||||
const Instruction *inst = (op < isa.count)? &isa.instructions[op]: NULL;
|
||||
if (!inst || !inst->name || !inst->binary_size) {
|
||||
break;
|
||||
}
|
||||
if (hbc_canonical_opcode_from_name (inst->name) == OP_DirectEval) {
|
||||
r_cons_printf (core->cons,
|
||||
"0x%08"PFMT64x" f=%u +0x%x func=0x%08"PFMT64x" name=%s\n",
|
||||
(ut64)HBC_VADDR_BASE + info.offset + pc, fid, pc,
|
||||
(ut64)HBC_VADDR_BASE + info.offset,
|
||||
r_str_get_fail (info.name, "unknown"));
|
||||
}
|
||||
pc += inst->binary_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Show file information */
|
||||
static void cmd_file_info(HbcContext *ctx, RCore *core) {
|
||||
Result res = hbc_load_current_binary (ctx, core);
|
||||
@@ -898,7 +848,6 @@ static void cmd_help(RCore *core) {
|
||||
" pd:h - Decompile function at current offset (or all if not in function)\n"
|
||||
" pd:hc [id] - Decompile function by id\n"
|
||||
" pd:ha - Decompile all functions\n"
|
||||
" pd:he - List functions containing eval instructions\n"
|
||||
" pd:hf - List all functions\n"
|
||||
" pd:hi - Show file information\n"
|
||||
" pd:hj [id] - JSON output for function\n"
|
||||
@@ -942,9 +891,6 @@ static bool cmd_handler(RCorePluginSession *s, const char *input) {
|
||||
case 'c': /* pd:hc [id] */
|
||||
cmd_decompile_function_ex (ctx, core, arg + 1, false);
|
||||
break;
|
||||
case 'e': /* pd:he */
|
||||
cmd_list_eval_functions (ctx, core);
|
||||
break;
|
||||
case 'f': /* pd:hf */
|
||||
cmd_list_functions (ctx, core);
|
||||
break;
|
||||
|
||||
+1
-62
@@ -879,14 +879,6 @@ static void json_print_string(const char *s) {
|
||||
putchar ('"');
|
||||
}
|
||||
|
||||
static void json_print_nullable_string(const char *s) {
|
||||
if (s) {
|
||||
json_print_string (s);
|
||||
} else {
|
||||
fputs ("null", stdout);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *binding_type_name(HBCBindingType type) {
|
||||
return type == HBC_BINDING_EXPORT? "export": "import";
|
||||
}
|
||||
@@ -935,58 +927,6 @@ static Result cmd_bind(const CliContext *ctx, int argc, char **argv) {
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
static Result cmd_libs(const CliContext *ctx, int argc, char **argv) {
|
||||
if (argc != 1) {
|
||||
return errorf (RESULT_ERROR_INVALID_ARGUMENT, "Usage: libs <input>");
|
||||
}
|
||||
HBC *hbc;
|
||||
RETURN_IF_ERROR (open_hbc (argv[0], &hbc));
|
||||
HBCModules modules = { 0 };
|
||||
Result r = hbc_list_modules (hbc, &modules);
|
||||
if (r.code != RESULT_SUCCESS) {
|
||||
hbc_close (hbc);
|
||||
return r;
|
||||
}
|
||||
if (ctx->flags.json) {
|
||||
putchar ('[');
|
||||
for (u32 i = 0; i < modules.count; i++) {
|
||||
HBCModule *m = &modules.modules[i];
|
||||
printf ("%s{\"kind\":", i? ",": "");
|
||||
json_print_string (m->kind);
|
||||
printf (",\"name\":");
|
||||
json_print_string (m->name);
|
||||
printf (",\"path\":");
|
||||
json_print_nullable_string (m->path);
|
||||
printf (",\"version\":");
|
||||
json_print_nullable_string (m->version);
|
||||
printf (",\"function_id\":%u,\"offset\":%u,\"string_id\":%u,\"inferred\":%s}",
|
||||
m->function_id, m->offset, m->string_id, m->inferred? "true": "false");
|
||||
}
|
||||
puts ("]");
|
||||
} else {
|
||||
printf ("libs: %u\n", modules.count);
|
||||
for (u32 i = 0; i < modules.count; i++) {
|
||||
HBCModule *m = &modules.modules[i];
|
||||
printf ("%-8s sid=%-5u fn=%-5u off=0x%08x %-30s",
|
||||
m->kind? m->kind: "", m->string_id, m->function_id,
|
||||
m->offset, m->name? m->name: "");
|
||||
if (m->version && *m->version) {
|
||||
printf (" version=%s", m->version);
|
||||
}
|
||||
if (m->path && *m->path && (!m->name || strcmp (m->path, m->name))) {
|
||||
printf (" path=%s", m->path);
|
||||
}
|
||||
if (m->inferred) {
|
||||
printf (" inferred");
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
}
|
||||
hbc_free_modules (&modules);
|
||||
hbc_close (hbc);
|
||||
return SUCCESS_RESULT ();
|
||||
}
|
||||
|
||||
static const Command commands[] = {
|
||||
{ "d", "Disassemble a Hermes bytecode file", cmd_d },
|
||||
{ "c", "Decompile a Hermes bytecode file", cmd_c },
|
||||
@@ -1005,7 +945,6 @@ static const Command commands[] = {
|
||||
{ "sm", "Show string entry metadata", cmd_sm },
|
||||
{ "lit", "SLP buffer literals: list, get, pool, xrefs", cmd_lit },
|
||||
{ "bind", "List probable imports/exports/native bindings", cmd_bind },
|
||||
{ "libs", "List probable bundled modules/libraries", cmd_libs },
|
||||
};
|
||||
#define COMMANDS_N (sizeof (commands) / sizeof (commands[0]))
|
||||
|
||||
@@ -1015,7 +954,7 @@ static void print_usage(const char *program_name) {
|
||||
printf (" %-5s %s\n", commands[i].name, commands[i].help);
|
||||
}
|
||||
printf ("\nOptions (may appear anywhere after the command):\n");
|
||||
printf (" --json, -j JSON output (lit list, bind, libs)\n");
|
||||
printf (" --json, -j JSON output (lit list)\n");
|
||||
printf (" --asmsyntax CPU-like asm syntax (dis)\n");
|
||||
printf (" --verbose, -v Verbose output\n");
|
||||
printf (" --bytecode, -b Include bytecode bytes\n");
|
||||
|
||||
@@ -18,16 +18,6 @@ EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:h help eval command
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:h?~pd:he
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
pd:he - List functions containing eval instructions
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hi file info small
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
@@ -136,26 +126,6 @@ EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:he list eval sites
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:he
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x100000b4 f=0 +0x4 func=0x100000b0 name=global
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:he list eval sites large
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
pd:he
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x100d166b f=4953 +0x28 func=0x100d1643 name=onPress
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hc decompile function return
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
NAME=hbc ih header fields
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
ih~version
|
||||
ih~functionCount
|
||||
ih~debugInfoOffset
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x00000008 0x00000008 0x00000060 version
|
||||
0x00000028 0x00000028 0x00000001 functionCount
|
||||
0x00000068 0x00000068 0x000000c8 debugInfoOffset
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc ihq header fields
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
ihq~version
|
||||
ihq~functionCount
|
||||
ihq~debugInfoOffset
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x00000008 0x00000060 version
|
||||
0x00000028 0x00000001 functionCount
|
||||
0x00000068 0x000000c8 debugInfoOffset
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc ihj header fields
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
ihj~{}~version
|
||||
ihj~{}~functionCount
|
||||
ihj~{}~debugInfoOffset
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
"name": "version",
|
||||
"name": "functionCount",
|
||||
"name": "debugInfoOffset",
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc iH ascii header
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
iH~version
|
||||
iH~functionCount
|
||||
iH~debugInfoOffset
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x00000008 version 0x00000060
|
||||
0x00000028 functionCount 0x00000001
|
||||
0x00000068 debugInfoOffset 0x000000c8
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc iH key values
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
iH=~version
|
||||
iH=~functionCount
|
||||
iH=~debugInfoOffset
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
version=96
|
||||
functionCount=1
|
||||
debugInfoOffset=200
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=hbc iH json
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
iHj~version
|
||||
iHj~functionCount
|
||||
iHj~debugInfoOffset
|
||||
EOF
|
||||
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}
|
||||
{"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}
|
||||
{"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
|
||||
@@ -1,172 +0,0 @@
|
||||
NAME=pd:hs help entry
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:h?~pd:hs
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
pd:hs [id] - List source-line information
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hs source lines small
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:hs
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x000000b0 f=0 +0x0 yes.js:1:1 stmt=0
|
||||
0x000000b4 f=0 +0x4 yes.js:1:5 stmt=0
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hs source lines filter
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:hs 0
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
0x000000b0 f=0 +0x0 yes.js:1:1 stmt=0
|
||||
0x000000b4 f=0 +0x4 yes.js:1:5 stmt=0
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hs source lines filter miss
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:hs 99
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hs empty source lines
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
pd:hs
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hi debug info present
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:hi~Debug Info Present
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
Debug Info Present: yes
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hi source locations size
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:hi~Source Locations
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
Source Locations: 13 bytes
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=pd:hi debug files count
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
pd:hi~Debug Files
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
Debug Files: 1 (6 bytes)
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=iI linenum exposed (debug info)
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
CMDS=<<EOF
|
||||
iI~linenum
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
linenum true
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=iI linenum stripped
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
iI~linenum
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
linenum false
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=iI linenum honours file truth with bin.dbginfo=false
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e bin.dbginfo=false
|
||||
CMDS=<<EOF
|
||||
iI~linenum,stripped
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
linenum true
|
||||
stripped false
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=iI stripped file still stripped with bin.dbginfo=false
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
ARGS=-e bin.dbginfo=false
|
||||
CMDS=<<EOF
|
||||
iI~linenum,stripped
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
linenum false
|
||||
stripped true
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=iI stripped file stripped with bin.dbginfo=true
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
ARGS=-e bin.dbginfo=true
|
||||
CMDS=<<EOF
|
||||
iI~linenum,stripped
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
linenum false
|
||||
stripped true
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=CL populated with bin.dbginfo=true
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e bin.dbginfo=true
|
||||
CMDS=<<EOF
|
||||
CL
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
file: yes.js
|
||||
line: 1
|
||||
colu: 1
|
||||
addr: 0x100000b0
|
||||
file: yes.js
|
||||
line: 1
|
||||
colu: 5
|
||||
addr: 0x100000b4
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=CL empty with bin.dbginfo=false
|
||||
FILE=bins/hbc/bespoke_eval.hbc
|
||||
ARGS=-e bin.dbginfo=false
|
||||
CMDS=<<EOF
|
||||
CL
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=CL empty on stripped file
|
||||
FILE=bins/hbc/index.android.bundle
|
||||
CMDS=<<EOF
|
||||
CL
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
EOF
|
||||
RUN
|
||||
Reference in new issue
Block a user