当前位置:Gxlcms > 数据库问题 > gdb通过frame切换栈帧之后寄存器是否准确

gdb通过frame切换栈帧之后寄存器是否准确

时间:2021-07-01 10:21:17 帮助过:57人阅读

.

三、调试信息的生成

由于源文件对编译器来说是比较完整的信息,所以生成的debug信息比较完整;相对的,如果是汇编语言,那么生成的调试信息可能就比较有限。为了解决这个问题,其实汇编中也可以插入一些指示,来帮助编译器生成调试信息:
glibc-2.10.1\sysdeps\generic\sysdep.h
#ifdef __ASSEMBLER__
/* Mark the end of function named SYM. This is used on some platforms
to generate correct debugging information. */
#ifndef END
#define END(sym)
#endif

#ifndef JUMPTARGET
#define JUMPTARGET(sym) sym
#endif

/* Makros to generate eh_frame unwind information. */
# ifdef HAVE_ASM_CFI_DIRECTIVES
# define cfi_startproc .cfi_startproc
# define cfi_endproc .cfi_endproc
# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off
# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg
# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off
# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
# define cfi_offset(reg, off) .cfi_offset reg, off
# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
# define cfi_register(r1, r2) .cfi_register r1, r2
# define cfi_return_column(reg) .cfi_return_column reg
# define cfi_restore(reg) .cfi_restore reg
# define cfi_same_value(reg) .cfi_same_value reg
# define cfi_undefined(reg) .cfi_undefined reg
# define cfi_remember_state .cfi_remember_state
# define cfi_restore_state .cfi_restore_state
# define cfi_window_save .cfi_window_save

四、gdb通过扫描函数prologue来恢复栈帧

从实现上看,gdb在没有调试信息的时候,只会扫描函数开始时的push指令。
gdb-7.7\gdb\i386-tdep.c
static CORE_ADDR
i386_analyze_prologue (struct gdbarch *gdbarch,
CORE_ADDR pc, CORE_ADDR current_pc,
struct i386_frame_cache *cache)
{
pc = i386_skip_noop (pc);
pc = i386_follow_jump (gdbarch, pc);
pc = i386_analyze_struct_return (pc, current_pc, cache);
pc = i386_skip_probe (pc);
pc = i386_analyze_stack_align (pc, current_pc, cache);
pc = i386_analyze_frame_setup (gdbarch, pc, current_pc, cache);
return i386_analyze_register_saves (pc, current_pc, cache);
}
static CORE_ADDR
i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
struct i386_frame_cache *cache)
{
CORE_ADDR offset = 0;
gdb_byte op;
int i;

if (cache->locals > 0)
offset -= cache->locals;
for (i = 0; i < 8 && pc < current_pc; i++)
{
if (target_read_code (pc, &op, 1))
return pc;
if (op < 0x50 || op > 0x57)
break;

offset -= 4;
cache->saved_regs[op - 0x50] = offset;
cache->sp_offset += 4;
pc++;
}

return pc;
}

五、测试下下寄存器的恢复情况

测试方法是制造一个core,首先在顶层栈帧断点并查看寄存器,等到core发生时再frame到顶层查看寄存器
tsecer@harry: cat -n gdbframe.cpp
1 #include <stdlib.h>
2 #include <string.h>
3
4 int main(int argc, char * argv[])
5 {
6 char *pAddr = NULL;
7 if ( argc > 0)
8 {
9 pAddr = (char*)malloc(0x100);
10 }
11 else if (argc > 2)
12 {
13 pAddr = (char*)malloc(0x200);
14 }
15 for (int i = 0; i < 0x100; i++)
16 {
17 pAddr[-i] = 0;
18 }
19 free(pAddr);
20 return 0;
21 }
tsecer@harry: g++ -g gdbframe.cpp
tsecer@harry: gdb ./a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-75.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/tsecer/CodeTest/gdbframe/a.out...done.
(gdb) b 19
Breakpoint 1 at 0x804850e: file gdbframe.cpp, line 19.
(gdb) r
Starting program: /home/tsecer/CodeTest/gdbframe/a.out

Breakpoint 1, main (argc=1, argv=0xbffff4c4) at gdbframe.cpp:19
19 free(pAddr);
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6.i686 libgcc-4.4.7-11.el6.i686 libstdc++-4.4.7-11.el6.i686
(gdb) info reg
eax 0x8049f00 134520576
ecx 0x109 265
edx 0x0 0
ebx 0x7e2ff4 8269812
esp 0xbffff3f0 0xbffff3f0
ebp 0xbffff418 0xbffff418
esi 0x0 0
edi 0x0 0
eip 0x804850e 0x804850e <main(int, char**)+106>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) c
Continuing.
*** glibc detected *** /home/tsecer/CodeTest/gdbframe/a.out: free(): invalid pointer: 0x0804a008 ***
======= Backtrace: =========
/lib/libc.so.6[0x6c1b91]
/home/tsecer/CodeTest/gdbframe/a.out[0x804851a]
/lib/libc.so.6(__libc_start_main+0xe6)[0x667d36]
/home/tsecer/CodeTest/gdbframe/a.out[0x8048411]
======= Memory map: ========
00110000-00111000 r-xp 00000000 00:00 0 [vdso]
0062b000-00649000 r-xp 00000000 08:02 135171 /lib/ld-2.12.so
00649000-0064a000 r--p 0001d000 08:02 135171 /lib/ld-2.12.so
0064a000-0064b000 rw-p 0001e000 08:02 135171 /lib/ld-2.12.so
00651000-007e1000 r-xp 00000000 08:02 135262 /lib/libc-2.12.so
007e1000-007e3000 r--p 00190000 08:02 135262 /lib/libc-2.12.so
007e3000-007e4000 rw-p 00192000 08:02 135262 /lib/libc-2.12.so
007e4000-007e7000 rw-p 00000000 00:00 0
00818000-00840000 r-xp 00000000 08:02 135278 /lib/libm-2.12.so
00840000-00841000 r--p 00027000 08:02 135278 /lib/libm-2.12.so
00841000-00842000 rw-p 00028000 08:02 135278 /lib/libm-2.12.so
059be000-059db000 r-xp 00000000 08:02 135303 /lib/libgcc_s-4.4.7-20120601.so.1
059db000-059dc000 rw-p 0001d000 08:02 135303 /lib/libgcc_s-4.4.7-20120601.so.1
059fa000-05adb000 r-xp 00000000 08:02 284438 /usr/lib/libstdc++.so.6.0.13
05adb000-05adf000 r--p 000e0000 08:02 284438 /usr/lib/libstdc++.so.6.0.13
05adf000-05ae1000 rw-p 000e4000 08:02 284438 /usr/lib/libstdc++.so.6.0.13
05ae1000-05ae7000 rw-p 00000000 00:00 0
08048000-08049000 r-xp 00000000 08:02 302465 /home/tsecer/CodeTest/gdbframe/a.out
08049000-0804a000 rw-p 00000000 08:02 302465 /home/tsecer/CodeTest/gdbframe/a.out
0804a000-0806b000 rw-p 00000000 00:00 0 [heap]
b7fee000-b7ff1000 rw-p 00000000 00:00 0
b7ffe000-b8000000 rw-p 00000000 00:00 0
bffeb000-c0000000 rw-p 00000000 00:00 0 [stack]

Program received signal SIGABRT, Aborted.
0x00110424 in __kernel_vsyscall ()
(gdb) bt
#0 0x00110424 in __kernel_vsyscall ()
#1 0x0067b871 in raise () from /lib/libc.so.6
#2 0x0067d14a in abort () from /lib/libc.so.6
#3 0x006bb735 in __libc_message () from /lib/libc.so.6
#4 0x006c1b91 in malloc_printerr () from /lib/libc.so.6
#5 0x0804851a in main (argc=1, argv=0xbffff4c4) at gdbframe.cpp:19
(gdb) f 5
#5 0x0804851a in main (argc=1, argv=0xbffff4c4) at gdbframe.cpp:19
19 free(pAddr);
(gdb) info reg
eax 0x0 0
ecx 0x539f 21407
edx 0x6 6
ebx 0x7e2ff4 8269812
esp 0xbffff3f0 0xbffff3f0
ebp 0xbffff418 0xbffff418
esi 0x0 0
edi 0x0 0
eip 0x804851a 0x804851a <main(int, char**)+118>
eflags 0x200246 [ PF ZF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb)

比较寄存器的输出,可以看到,挥发性寄存器eax、ecx、edx的值都没有正确恢复
tsecer@harry: diff frame current
1,3c1,3
< eax 0x0 0
< ecx 0x539f 21407
< edx 0x6 6
---
> eax 0x8049f00 134520576
> ecx 0x109 265
> edx 0x0 0
9c9
< eip 0x804851a 0x804851a <main(int, char**)+118>
---
> eip 0x804850e 0x804850e <main(int, char**)+106>
tsecer@harry:

六、为什么不能恢复

if (……)

{
$eax = x
}
else
{
$eax = y
}
funccall();
假设通过frame返回funccall,此时根本不知道在调用前走的是哪个分支,所以无法恢复eax寄存器。而非挥发寄存器被调用函数会在prologue中通过push保存,所以恢复比较简单。

gdb通过frame切换栈帧之后寄存器是否准确

标签:color   rate   sele   汇编语言   rds   content   byte   mos   cache   

人气教程排行