174 lines
4.4 KiB
JavaScript
174 lines
4.4 KiB
JavaScript
//
|
|
// Utility functions.
|
|
//
|
|
// Copyright (c) 2016 Samuel Groß
|
|
//
|
|
|
|
// Return the hexadecimal representation of the given byte.
|
|
function hex(b) {
|
|
return ('0' + b.toString(16)).substr(-2);
|
|
}
|
|
|
|
// Return the hexadecimal representation of the given byte array.
|
|
function hexlify(bytes) {
|
|
var res = [];
|
|
for (var i = 0; i < bytes.length; i++)
|
|
res.push(hex(bytes[i]));
|
|
|
|
return res.join('');
|
|
}
|
|
|
|
// Return the binary data represented by the given hexdecimal string.
|
|
function unhexlify(hexstr) {
|
|
if (hexstr.length % 2 == 1)
|
|
throw new TypeError("Invalid hex string");
|
|
|
|
var bytes = new Uint8Array(hexstr.length / 2);
|
|
for (var i = 0; i < hexstr.length; i += 2)
|
|
bytes[i/2] = parseInt(hexstr.substr(i, 2), 16);
|
|
|
|
return bytes;
|
|
}
|
|
|
|
function hexdump(data) {
|
|
if (typeof data.BYTES_PER_ELEMENT !== 'undefined')
|
|
data = Array.from(data);
|
|
|
|
var lines = [];
|
|
for (var i = 0; i < data.length; i += 16) {
|
|
var chunk = data.slice(i, i+16);
|
|
var parts = chunk.map(hex);
|
|
if (parts.length > 8)
|
|
parts.splice(8, 0, ' ');
|
|
lines.push(parts.join(' '));
|
|
}
|
|
|
|
return lines.join('\n');
|
|
}
|
|
|
|
function strcmp(b, str)
|
|
{
|
|
var fn = typeof b == "function" ? b : function(i) { return b[i]; };
|
|
for(var i = 0; i < str.length; ++i)
|
|
{
|
|
if(fn(i) != str.charCodeAt(i))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return fn(str.length) == 0;
|
|
}
|
|
|
|
function b2u32(b)
|
|
{
|
|
return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
|
|
}
|
|
|
|
function off2addr(segs, off)
|
|
{
|
|
if(!(off instanceof Int64)) off = new Int64(off);
|
|
for(var i = 0; i < segs.length; ++i)
|
|
{
|
|
var start = segs[i].fileoff;
|
|
var end = Add(start, segs[i].size);
|
|
if
|
|
(
|
|
(start.hi() < off.hi() || (start.hi() == off.hi() && start.lo() <= off.lo())) &&
|
|
(end.hi() > off.hi() || (end.hi() == off.hi() && end.lo() > off.lo()))
|
|
)
|
|
{
|
|
return Add(segs[i].addr, Sub(off, start));
|
|
}
|
|
}
|
|
return new Int64("0x4141414141414141");
|
|
}
|
|
|
|
function fsyms(mem, base, segs, want, syms)
|
|
{
|
|
want = Array.from(want); // copy
|
|
if(syms === undefined)
|
|
{
|
|
syms = {};
|
|
}
|
|
|
|
var stab = null;
|
|
var ncmds = mem.u32(Add(base, 0x10));
|
|
for(var i = 0, off = 0x20; i < ncmds; ++i)
|
|
{
|
|
var cmd = mem.u32(Add(base, off));
|
|
if(cmd == 0x2) // LC_SYMTAB
|
|
{
|
|
var b = mem.read(Add(base, off + 0x8), 0x10);
|
|
stab =
|
|
{
|
|
symoff: b2u32(b.slice(0x0, 0x4)),
|
|
nsyms: b2u32(b.slice(0x4, 0x8)),
|
|
stroff: b2u32(b.slice(0x8, 0xc)),
|
|
strsize: b2u32(b.slice(0xc, 0x10)),
|
|
};
|
|
break;
|
|
}
|
|
off += mem.u32(Add(base, off + 0x4));
|
|
}
|
|
if(stab == null)
|
|
{
|
|
fail("stab");
|
|
}
|
|
var tmp = { base: off2addr(segs, stab.stroff), off: 0 };
|
|
var fn = function(i)
|
|
{
|
|
return mem.read(Add(tmp.base, tmp.off + i), 1)[0];
|
|
};
|
|
for(var i = 0; i < stab.nsyms && want.length > 0; ++i)
|
|
{
|
|
tmp.off = mem.u32(off2addr(segs, stab.symoff + i * 0x10));
|
|
for(var j = 0; j < want.length; ++j)
|
|
{
|
|
var s = want[j];
|
|
if((strcmp(fn, s)))
|
|
{
|
|
syms[s] = mem.readInt64(off2addr(segs, stab.symoff + i * 0x10 + 0x8));
|
|
want.splice(j, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return syms;
|
|
}
|
|
|
|
function _u32(i)
|
|
{
|
|
return b2u32(this.read(i, 4));
|
|
}
|
|
|
|
// Simplified version of the similarly named python module.
|
|
var Struct = (function() {
|
|
// Allocate these once to avoid unecessary heap allocations during pack/unpack operations.
|
|
var buffer = new ArrayBuffer(8);
|
|
var byteView = new Uint8Array(buffer);
|
|
var uint32View = new Uint32Array(buffer);
|
|
var float64View = new Float64Array(buffer);
|
|
|
|
return {
|
|
pack: function(type, value) {
|
|
var view = type; // See below
|
|
view[0] = value;
|
|
return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT);
|
|
},
|
|
|
|
unpack: function(type, bytes) {
|
|
if (bytes.length !== type.BYTES_PER_ELEMENT)
|
|
throw Error("Invalid bytearray");
|
|
|
|
var view = type; // See below
|
|
byteView.set(bytes);
|
|
return view[0];
|
|
},
|
|
|
|
// Available types.
|
|
int8: byteView,
|
|
int32: uint32View,
|
|
float64: float64View
|
|
};
|
|
})();
|