如何通过查看堆栈值来生成回溯?
测验:如何通过查看堆栈值来生成回溯?
0xf3e2de34 f3e2de70 c0135351 401ef021 00000000 p.bsQS...p......
0xf3e2de44 f3e2de81 00000021 f3e2c000 f7950924 ..bs......bs...w
0xf3e2de54 00000000 401ef000 00000246 00000246 .....p..F...F...
0xf3e2de64 00000001 00000001 f7950000 f3e2df18 ...........w..bs
0xf3e2de74 c02898b5 322d7875 23203235 00007820 5...ux.252...x..
0xf3e2de84 f3e2de98 00000000 f7950bd0 bffff0ec ..bs....P..wlp..
0xf3e2de94 c70cf660 00000000 00000000 bffff0ec .v.G........lp..
0xf3e2dea4 f3e2c000 f7950930 7fffffff 00000000 ..bs0..w........
0xf3e2deb4 00000000 00000001 00000000 bffff07b .............p..
0xf3e2dec4 f5cfd880 bffff07b 00000000 f5f24740 .XOu.p.......Gru
0xf3e2ded4 c0124f87 00000000 00000000 00200200 .O..............
0xf3e2dee4 f3e2defc 067b3067 00000000 f5f24740 ..bsg0.......Gru
0xf3e2def4 c0124f87 f7950934 f7950934 c028331b .O..4..w4..w.3..
0xf3e2df04 00000000 c01b0fe8 f5cfd880 f7950000 ....h....XOu...w
0xf3e2df14 fffffffb f3e2df50 c0283642 00000001 ....P.bsB6......
0xf3e2df24 00000001 00000001 f3e2c000 f6fe30d0 ..........bsP0.v
提示 - 当前函数始终可以从 EIP 确定
我在 kernelnewbies/ABI 文档。
我真的不明白那里给出的提示?(也许是因为我不知道这件事)。
有人可以解释一下如何解决这些类似的问题吗?
Quiz : How to generate the backtrace by looking at the stack values?
0xf3e2de34 f3e2de70 c0135351 401ef021 00000000 p.bsQS...p......
0xf3e2de44 f3e2de81 00000021 f3e2c000 f7950924 ..bs......bs...w
0xf3e2de54 00000000 401ef000 00000246 00000246 .....p..F...F...
0xf3e2de64 00000001 00000001 f7950000 f3e2df18 ...........w..bs
0xf3e2de74 c02898b5 322d7875 23203235 00007820 5...ux.252...x..
0xf3e2de84 f3e2de98 00000000 f7950bd0 bffff0ec ..bs....P..wlp..
0xf3e2de94 c70cf660 00000000 00000000 bffff0ec .v.G........lp..
0xf3e2dea4 f3e2c000 f7950930 7fffffff 00000000 ..bs0..w........
0xf3e2deb4 00000000 00000001 00000000 bffff07b .............p..
0xf3e2dec4 f5cfd880 bffff07b 00000000 f5f24740 .XOu.p.......Gru
0xf3e2ded4 c0124f87 00000000 00000000 00200200 .O..............
0xf3e2dee4 f3e2defc 067b3067 00000000 f5f24740 ..bsg0.......Gru
0xf3e2def4 c0124f87 f7950934 f7950934 c028331b .O..4..w4..w.3..
0xf3e2df04 00000000 c01b0fe8 f5cfd880 f7950000 ....h....XOu...w
0xf3e2df14 fffffffb f3e2df50 c0283642 00000001 ....P.bsB6......
0xf3e2df24 00000001 00000001 f3e2c000 f6fe30d0 ..........bsP0.v
Hint - the current function can always be determined from EIP
I found this question at kernelnewbies/ABI documentation.
I really dont understand the hint given there?(Maybe because i have no idea about this thing).
Could somebody explain me how to solve these kinda questions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在这种情况下,您可以非常可靠地完成此操作,因为该代码是在启用帧指针的情况下编译的。
您需要了解的是:
调用函数时,参数和 EIP(因此被调用函数知道返回到哪里)保存在堆栈上。
当编译器被告知(显式或隐式)使用帧指针时,它会将帧指针(在 EBP 寄存器中)保存在堆栈上(以便稍后可以将帧指针恢复为它在堆栈上的值)调用函数),然后将帧指针设置为指向当前堆栈顶部。这允许从已知的引用点(帧指针)轻松访问参数和局部变量,并大大简化调试。
因此,要生成回溯,您需要跟踪帧指针,查看相应的已保存 EIPS。所以:
当然,这是最简单的情况。当你没有帧指针时,你必须猜测堆栈上的给定值是否对应于指令指针。
缺少的部分是如何将这些数字转换为函数名称。拥有一个未剥离的
vmlinux
(注意x
,而不是z
)文件是非常宝贵的。System.map
仅包含一些符号,因此通常您最终只能知道相关函数位于函数 A 和函数 B 之间。编辑:
函数调用x86 看起来像:
被调用的函数看起来像:
因此,堆栈看起来类似于:
(较低的地址在 ASCII 艺术上较低)
所以,如果您继续跟踪保存的
EBP
指针,你可以得到保存的EIP
指针(上面的ret
),它指向调用链中的指令(准确地说是返回链中)。In this case, you can do it quite reliably, since that code has been compiled with frame pointers enabled.
What you need to know:
When calling a function, the arguments and then EIP (so the called function knows where to return to) are saved on the stack.
When the compiler has been told (explicitly or implicitly) to use frame pointers, it then saves the frame pointer (in the EBP register) on the stack (so it can later restore the frame pointer to the value it had on the calling function), and then sets the frame pointer to point to the current top of the stack. This allows accessing easily arguments and local variables from a known point of reference (the frame pointer), and greatly simplifies debugging.
So, to generate a backtrace, you would follow the frame pointers, looking at the corresponding saved EIPS. So:
Of course, this was the easy case. When you don't have frame pointers, you have to guess whether a given value on the stack corresponds to an instruction pointer.
The missing part is how to translate this numbers to function names. Having an unstripped
vmlinux
(note thex
, not az
) file is invaluable.System.map
just contains some symbols, so very often you'll only end up knowing that the relevant function was between function A and function B.Edit:
A function call on x86 looks something like:
And the called function looks something like:
So, the stack will look similar to:
(Lower addresses are lower on the ASCII-art)
So, if you keep following the saved
EBP
pointers, you can get the savedEIP
pointers (ret
above), which point to instructions in the call chain (in the return chain, to be precise).我认为EIP是指令指针——它保存当前正在执行的指令的地址。
The EIP is the instruction pointer I think - it holds the address of the instruction being executed at the moment.