###Problem
jQuery and other libraries often use a poor man's bind:
// jQuery's proxy method.
let outer = {
fn: {
proxy: function(fn) {
return function() {
return fn.apply(this, arguments);
};
}
}
}
// Function that we are to proxy
function unwrapped() {
alert("Howdy y'all");
}
// Bind the function
let proxied = outer.fn.proxy(unwrapped);
let dblProxied = outer.fn.proxy(proxied);
dblProxied() // displays the popup
dblProxied.toString() // function() { return fn.apply(this, arguments);}
We can get the original function like this:
globalDO.makeDebuggeeValue(dblProxied).environment.getValue("fn").environment.getValue("fn")
The problem with this approach is that when libraries are minified variable names change and between library versions their index can also change. On top of this there is the problem that there can be multiple functions stored as variables within scope so simply iterating over variables and checking for class === "Function"
rarely works.
###Solution?
What we really need is a way to get the original function that will be executed when dblProxied is called. Something like this:
globalDO.makeDebuggeeValue(dblProxied).getOriginator()
This solution would have the advantage of working with a lot of libraries.
###Scratchpad
var code = "// jQuery's proxy method.\n" +
"var outer = {\n" +
" fn: {\n" +
" proxy: function(fn) {\n" +
" return function() {\n" +
" return fn.apply(this, arguments);\n" +
" };\n" +
" }\n" +
" }\n" +
"};\n" +
"\n" +
"// Function that we are to proxy\n" +
"function unwrapped() {\n" +
" alert(\"Howdy y'all\");\n" +
"}\n" +
"\n" +
"// Bind the function\n" +
"var proxied = outer.fn.proxy(unwrapped);\n" +
"var dblProxied = outer.fn.proxy(proxied);\n";
var sandbox = new Cu.Sandbox("http://www.example.com");
sandbox.alert = alert;
Cu.evalInSandbox(code, sandbox);
var dblProxied = sandbox.dblProxied;
Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);
var dbg = new Debugger;
var globalDO = dbg.addDebuggee(sandbox);
var fn = globalDO.makeDebuggeeValue(dblProxied).environment.getVariable("fn")
.environment.getVariable("fn");
var rv = globalDO.evalInGlobalWithBindings("fn.toString()", {fn: fn});
alert(rv.return);