Home | History | Annotate | Download | only in ReverseDebug
      1 This is a tutorial/unittest for gdb's reverse debugging feature. It is a new
      2 feature that allows users to take a snapshot of the machine state, continue
      3 until a later stage of the program, then return to the previously recorded
      4 state and execute again. An ideal usage case is to help track down the reason
      5 why a memory location is clobbered. 
      6 
      7 In the sample below, the "clobber" function trashes a neighboring variable "p"
      8 on the stack next to the "values" variable, and the program will crash at
      9 line 42 when "p" is being dereferenced.
     10 
     11  18 #include <stdio.h>
     12  19 #include <stdlib.h>
     13  20 
     14  21 #define ARRAY_LENGTH 10
     15  22 
     16  23 int flag;
     17  24 
     18  25 void clobber(int *array, int size) {
     19  26     /* Make sure it clobbers something. */
     20  27     array[-1] = 0x123;
     21  28     array[size] = 0x123;
     22  29 }
     23  30 
     24  31 int main(void) {
     25  32     int values[ARRAY_LENGTH];
     26  33     int *p = (int *) malloc(sizeof(int));
     27  34     *p = 10;
     28  35 
     29  36     while (!flag) {
     30  37         sleep(1);
     31  38     }
     32  39 
     33  40     /* Set a breakpint here: "b main.c:41" */
     34  41     clobber(values, ARRAY_LENGTH);
     35  42     printf("*p = %d\n", *p);
     36  43     free(p);
     37  44 
     38  45     return 0;
     39  46 }
     40 
     41 The test program can be built/installed on the device by doing:
     42 
     43 > mmm development/tutorials/ReverseDebug
     44 > adb sync
     45 > adb shell reverse_debug
     46 
     47 In another window the following command can be used to attach to the running
     48 program:
     49 
     50 > gdbclient reverse_debug :5039 reverse_debug
     51 [1] 12802
     52 Attached; pid = 1842
     53 Listening on port 5039
     54 GNU gdb (GDB) 7.6
     55 Copyright (C) 2013 Free Software Foundation, Inc.
     56 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
     57 This is free software: you are free to change and redistribute it.
     58 There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
     59 and "show warranty" for details.
     60 This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
     61 For bug reporting instructions, please see:
     62 <http://source.android.com/source/report-bugs.html>...
     63 Reading symbols from /usr/local/google/work/master/out/target/product/manta/symbols/system/bin/reverse_debug...done.
     64 Remote debugging from host 127.0.0.1
     65 nanosleep () at bionic/libc/arch-arm/syscalls/nanosleep.S:10
     66 10      mov     r7, ip
     67 
     68 ====
     69 
     70 Now set a breakpoint on line 41 and set flag to 1 so that the program can
     71  continue. 
     72 
     73 (gdb) b main.c:41
     74 Breakpoint 1 at 0xb6f174a8: file development/tutorials/ReverseDebug/main.c, line 41.
     75 (gdb) p flag=1
     76 $1 = 1
     77 (gdb) c
     78 Continuing.
     79 
     80 ====
     81 
     82 Now try the new "record" command to take a snapshot of the machine state.
     83 
     84 Breakpoint 1, main () at development/tutorials/ReverseDebug/main.c:41
     85 41      clobber(values, ARRAY_LENGTH);
     86 (gdb) record
     87 (gdb) c
     88 Continuing.
     89 
     90 ====
     91 
     92 Now the program crashes as expected as "p" has been clobbered. The
     93 "reverse-continue" command will bring the program back to line 41 and let you
     94 replay each instruction from there.
     95 
     96 Program received signal SIGSEGV, Segmentation fault.
     97 0xb6f174bc in main () at development/tutorials/ReverseDebug/main.c:42
     98 42      printf("*p = %d\n", *p);
     99 (gdb) reverse-continue
    100 Continuing.
    101 
    102 No more reverse-execution history.
    103 main () at development/tutorials/ReverseDebug/main.c:41
    104 41      clobber(values, ARRAY_LENGTH);
    105 
    106 
    107 ====
    108 
    109 Now let's add a watch point at "&p" to hopefully catch the clobber on the spot:
    110  
    111 (gdb) watch *(&p)
    112 Hardware watchpoint 2: *(&p)
    113 (gdb) c
    114 Continuing.
    115 Hardware watchpoint 2: *(&p)
    116 
    117 ====
    118 
    119 And here it is:
    120 
    121 Old value = (int *) 0xb728c020
    122 New value = (int *) 0x123
    123 0xb6f17440 in clobber (array=0xbebcaab0, size=10)
    124     at development/tutorials/ReverseDebug/main.c:28
    125 28      array[size] = 0x123;
    126 
    127 
    128 ===============================
    129 
    130 That said, reverse debugging on ARM is still in the infant stage. Currently
    131 (as of gdb 7.6) it only recognizes ARM instructions and will punt on all
    132 Thumb(2) instructions. To give it a try you will need to recompile your
    133 program in ARM mode. To do that you have to add the ".arm" suffix to the
    134 desired file in Android.mk:
    135 
    136 LOCAL_SRC_FILES:= main.c.arm
    137 
    138