JS输出函数调用栈
最近在编写 JS 逆向 hook 类插件,然后需要 获取当前代码执行时所在的位置,方便代码定位,于是就总结下 JavaScript 如何输出函数调用栈。
演示代码
function main() {
let a = fun('hello world')
console.log(a)
}
function fun(a) {
return a
}
main()
方法
console.trace()
使用如下
function main() {
let a = fun('hello world')
console.log(a)
}
function fun(a) {
console.trace('fun')
return a
}
main()
输出结果为
Trace: fun
at fun (c:\Users\zeyu\Desktop\demo\main.js:7:11)
at main (c:\Users\zeyu\Desktop\demo\main.js:2:11)
at Object.<anonymous> (c:\Users\zeyu\Desktop\demo\main.js:11:1) at Module._compile (node:internal/modules/cjs/loader:1095:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1124:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:816:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
at node:internal/main/run_main_module:17:47
hello world
其中console.trace()
可以传入参数,最终都将直接输出在 Trace 后面,如这里的 fun,但只能在控制台中输出
不过 IE6 并不支持,不过应该也没人用了吧
arguments.callee.caller
在非严格模式下,可以直接输出arguments
,便会打印出所调用的参数,以及调用的函数,使用如下
function main() {
let a = fun('hello world')
console.log(a)
}
function fun(a) {
console.log(fun.caller.toString())
console.log(arguments)
console.log(arguments.callee.toString())
console.log(arguments.callee.caller.toString())
return a
}
main()
输出结果为
function main() {
let a = fun('hello world')
console.log(a)
}
[Arguments] { '0': 'hello world' }
function fun(a) {
console.log(fun.caller.toString())
console.log(arguments)
console.log(arguments.callee.toString())
console.log(arguments.callee.caller.toString())
return a
}
function main() {
let a = fun('hello world')
console.log(a)
}
hello world
成功的将我们当前运行的函数给打印了出来(这里使用 toString 方便将函数打印出来),而上级的函数的话通过fun.caller
和arguments.callee.caller
都能得到。
caller
便是调用的上层函数,也就是这里的 main 函数,不难发现每个 caller 对象下都有一个 caller 属性,也就是caller
的上层函数,由于我这里是 node 环境,所以这里的 caller 的 caller 我也不知道是个什么玩意。。。反正这不是所要关注的重点,重点是**fun.caller
和``arguments.callee.caller`便可以打印出上层函数**,直到 caller 为空
另外圈的[[FunctionLocation]]
便是函数所在位置,不过可惜是,这个并不是 caller 的属性,仅供 js 引擎使用的,所以无法输出。
总结下来:
fun.caller == arguments.callee.caller 代表 fun 的执行环境 (上层函数)
arguments.callee 代表的是正在执行的 fun
前提: 非严格模式下