After gdb register stack frame by frame switching accuracy

First, the problem

When using the register stack debugging some of the damaged core files, you may need to determine the cause of the problem through disassembly, but at this time to determine the value of the register is a necessary means. However, after switching stack frame by frame, seen through info reg register stack frame is the current value of the register it?

Two, gdb documented

if all stack frames farther in were exited and their saved registers restored. In order to see the true contents of hardware registers, you must select the innermost frame (with 'frame 0').
In summary, some values may vary with the volatile registers expand the stack frame and continuous accumulation of errors. It is mentioned here: if the stack frame by an outer layer, the value of the volatile registers, the easier these inaccuracies.
Usually ABIs reserve some registers as not needed to be saved by the callee (a.k.a.: “caller-saved”, “call-clobbered” or “volatile” registers). It may therefore not be possible for GDB to know the value a register had before the call (in other words, in the outer frame), if the register value has since been changed by the callee. GDB tries to deduce where the inner frame saved (“callee-saved”) registers, from the debug info, unwind info, or the machine code generated by your compiler. If some register is not saved, and GDB knows the register is “caller-saved” (via its own knowledge of the ABI, or because the debug/unwind info explicitly says the register’s value is undefined), GDB displays ‘<not saved>’ as the register’s value. With targets that GDB has no knowledge of the register saving convention, if a register was not saved by the callee, then its value and location in the outer frame are assumed to be the same of the inner frame. This is usually harmless, because if the register is call-clobbered, the caller either does not care what is in the register after the call, or has code to restore the value that it does care about. Note, however, that if you change such a register in the outer frame, you may also be affecting the inner frame. Also, the more “outer” the frame is you’re looking at, the more likely a call-clobbered register’s value is to be wrong, in the sense that it doesn’t actually represent the value the register had just before the call.

Third, debugging information generation

Because the source file is more complete information for the compiler, the generated debug information more complete; relative, if it is assembly language, then generate debug information may be more limited. To solve this problem, in fact, the compilation can also insert some instructions to help the compiler to generate debugging information:
glibc-2.10.1 \ sysdeps \ the Generic \ sysdep.h
#ifdef __ASSEMBLER__
/ * Mark at The End of This IS function named SYM. Platforms some ON Used
to Generate the debugging Information correct. * /
#ifndef the END
#define the 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

Four, gdb stack frame to restore the scanning function prologue

From the implementation point of view, gdb debugging in the absence of information, it will only push the scan command when the function begins.
7.7-GDB \ GDB \ tdep.c the i386-
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;
}

Recovery of five test under register

The test method is for manufacturing a core, in the first stack frame top view and breakpoint register until then to the top view the frame core register occurs
tsecer @ Harry: CAT -n gdbframe.cpp
. 1 #include <stdlib.h>
2 #include < string.h>
. 3
. 4 int main (int argc, char * the argv [])
. 5 {
. 6 pAddr char * = NULL;
. 7 IF (argc> 0)
. 8 {
. 9 pAddr = (char *) the malloc (0x100);
10}
. 11 the else IF (argc> 2)
12 is {
13 is pAddr = (char *) the malloc (0x200);
14}
15 for (int I = 0; I <0x100; I ++)
16 {
. 17 pAddr [-i] = 0;
18 is }
. 19 Free (pAddr);
20 is return 0;
21 is}
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)

The output compare register it can be seen that the value of the volatile register eax, ecx, edx are not correctly restored
tsecer @ Harry: the diff Current Frame
1,3c1,3
<EAX 0x0 0
<ECX 0x539f 21407
<EDX 0x6. 6
---
> EAX 0x8049f00 134 520 576
> 265 0x109 ECX
> 0 0x0 EDX
9c9
<0x804851a 0x804851a EIP <main (int, char **) + 1 18>
---
> EIP 0x804850e 0x804850e <main (int, char **) + 106>
tsecer @ harry:

Sixth, why can not recover

if (……)

{
$ Eax = X
}
the else
{
$ eax = Y
}
funccall ();
assuming returns funccall by Frame, do not know at this time before the call is to go in which branch, it is impossible to restore the eax register. Rather volatile register function being called push will be saved by the prologue, so recovery is relatively simple.

Guess you like

Origin www.cnblogs.com/tsecer/p/11371549.html