summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWouter van Oortmerssen <aardappel@gmail.com>2020-01-16 08:40:47 -0800
committerGitHub <noreply@github.com>2020-01-16 08:40:47 -0800
commit0fdf72711e23116750f1aff34cae57f0d5c55125 (patch)
tree2cf8d0d1f62bb306383a143e9691cde27e5ea8d9
parent256f868194bafc3ea32b981c51dd657151a04ae7 (diff)
downloadwabt-0fdf72711e23116750f1aff34cae57f0d5c55125.tar.gz
wabt-0fdf72711e23116750f1aff34cae57f0d5c55125.tar.bz2
wabt-0fdf72711e23116750f1aff34cae57f0d5c55125.zip
wasm-decompile: absolute accesses refer to data segments (#1302)
This makes them easier to look up than the large integer constants LLVM output is full of.
-rw-r--r--src/decompiler-ls.h8
-rw-r--r--src/decompiler.cc36
-rw-r--r--test/decompile/basic.txt2
-rw-r--r--test/decompile/loadstore.txt9
4 files changed, 48 insertions, 7 deletions
diff --git a/src/decompiler-ls.h b/src/decompiler-ls.h
index 80ec2654..3f59d6ce 100644
--- a/src/decompiler-ls.h
+++ b/src/decompiler-ls.h
@@ -78,7 +78,7 @@ struct LoadStoreTracking {
};
struct LSVar {
- std::map<uint32_t, LSAccess> accesses;
+ std::map<uint64_t, LSAccess> accesses;
bool struct_layout = true;
Type same_type = Type::Any;
Address same_align = kInvalidAddress;
@@ -119,7 +119,7 @@ struct LoadStoreTracking {
}
}
- void LoadStore(uint32_t offset, Opcode opc, Type type, Address align,
+ void LoadStore(uint64_t offset, Opcode opc, Type type, Address align,
const Node& addr_exp) {
auto byte_size = opc.GetMemorySize();
type = GetMemoryType(type, opc);
@@ -178,7 +178,7 @@ struct LoadStoreTracking {
var.second.struct_layout = false;
continue;
}
- uint32_t cur_offset = 0;
+ uint64_t cur_offset = 0;
uint32_t idx = 0;
for (auto& access : var.second.accesses) {
access.second.idx = idx++;
@@ -234,7 +234,7 @@ struct LoadStoreTracking {
return "";
}
- std::string GenAccess(uint32_t offset, const Node& addr_exp) const {
+ std::string GenAccess(uint64_t offset, const Node& addr_exp) const {
auto name = AddrExpName(addr_exp);
if (name.empty()) {
return "";
diff --git a/src/decompiler.cc b/src/decompiler.cc
index db71bf42..a0f710c4 100644
--- a/src/decompiler.cc
+++ b/src/decompiler.cc
@@ -224,7 +224,16 @@ struct Decompiler {
return cat(name, ":", struc.empty() ? GetDecompTypeName(t) : struc);
}
- void LoadStore(Value &val, const Node& addr_exp, uint32_t offset,
+ bool ConstIntVal(const Expr* e, uint64_t &dest) {
+ dest = 0;
+ if (!e || e->type() != ExprType::Const) return false;
+ auto& c = cast<ConstExpr>(e)->const_;
+ if (c.type != Type::I32 && c.type != Type::I64) return false;
+ dest = c.type == Type::I32 ? c.u32 : c.u64;
+ return true;
+ }
+
+ void LoadStore(Value &val, const Node& addr_exp, uint64_t offset,
Opcode opc, Address align, Type op_type) {
bool append_type = true;
auto access = lst.GenAccess(offset, addr_exp);
@@ -240,6 +249,30 @@ struct Decompiler {
return;
}
}
+ // Detect absolute addressing, which we try to turn into references to the
+ // data section when possible.
+ uint64_t abs_base;
+ if (ConstIntVal(addr_exp.e, abs_base)) {
+ // We don't care what part of the absolute address was stored where,
+ // 1[0] and 0[1] are the same.
+ abs_base += offset;
+ // FIXME: make this less expensive with a binary search or whatever.
+ for (auto dat : mc.module.data_segments) {
+ uint64_t dat_base;
+ if (dat->offset.size() == 1 &&
+ ConstIntVal(&dat->offset.front(), dat_base) &&
+ abs_base >= dat_base &&
+ abs_base < dat_base + dat->data.size()) {
+ // We are inside the range of this data segment!
+ // Turn expression into data_name[index]
+ val = Value { { dat->name }, Precedence::Atomic };
+ // The new offset is from the start of the data segment, instead of
+ // whatever it was.. this may be a different value from both the
+ // original const and offset!
+ offset = abs_base - dat_base;
+ }
+ }
+ }
// Do the load/store as a generalized indexing operation.
// The offset is divisible by the alignment in 99.99% of
// cases, but the spec doesn't guarantee it, so we must
@@ -697,7 +730,6 @@ struct Decompiler {
// Data.
for (auto dat : mc.module.data_segments) {
-
s += cat("data ", dat->name, "(offset: ", InitExp(dat->offset), ") = ");
auto ds = BinaryToString(dat->data);
if (ds.size() > target_exp_width / 2) {
diff --git a/test/decompile/basic.txt b/test/decompile/basic.txt
index e7a4c9db..7d6088ea 100644
--- a/test/decompile/basic.txt
+++ b/test/decompile/basic.txt
@@ -132,7 +132,7 @@ export function f(a:int, b:int):int {
var c:long = 8L;
var d:float = 6.0f;
var e:double = 7.0;
- if (e < 10.0) { 1[1]:int = 2[3]:int@1 + 5 }
+ if (e < 10.0) { d_a[5@4]:int = d_a[5]:int@1 + 5 }
f(a + g_b, 9);
loop L_b {
if (if (0) { 1 } else { 2 }) goto B_c;
diff --git a/test/decompile/loadstore.txt b/test/decompile/loadstore.txt
index ce3cc89f..65334cec 100644
--- a/test/decompile/loadstore.txt
+++ b/test/decompile/loadstore.txt
@@ -3,6 +3,8 @@
(module
(memory $m1 1)
+ (data 0 (offset (i32.const 10)) "Hello, World!\n\00")
+
(func $f (param i32 i32) (result) (local i32 i32 i32 i32 i32 i32)
;; Test regular accesses that become a struct.
get_local 0
@@ -95,6 +97,10 @@
i32.add
i32.load offset=4
i32.store offset=4
+ ;; Test naming of absolute addresses referring to data sections.
+ i32.const 16
+ i32.load8_u offset=1 ;; Refers to the 'W'
+ drop
)
(export "f" (func $f))
)
@@ -102,6 +108,8 @@
(;; STDOUT ;;;
memory M_a(initial: 1, max: 0);
+data d_a(offset: 10) = "Hello, World!\0a\00";
+
export function f(a:{ a:float, b:float }, b:{ a:ushort, b:long }) {
var c:{ a:float, b:float }
var d:{ a:ushort, b:long }
@@ -121,6 +129,7 @@ export function f(a:{ a:float, b:float }, b:{ a:ushort, b:long }) {
a[b]:int = a[b]:int;
a[b + 1]:int = a[b + 1]:int;
(a + (b << 3))[1]:int = a[b + 1]:int;
+ d_a[7]:ubyte;
}
;;; STDOUT ;;)