Add a new example/unittest for GDB's reverse debugging feature.
Change-Id: Ic55343957cd35dc41d2dcf9f436d1940cd454084
This commit is contained in:
28
tutorials/ReverseDebug/Android.mk
Normal file
28
tutorials/ReverseDebug/Android.mk
Normal file
@@ -0,0 +1,28 @@
|
||||
# Copyright (C) 2013 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ifneq ($(filter arm ,$(TARGET_ARCH)),)
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES:= main.c.arm
|
||||
|
||||
LOCAL_CFLAGS := -std=gnu99 -O0
|
||||
|
||||
LOCAL_MODULE := reverse_debug
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
endif # arm in TARGET_ARCH
|
||||
137
tutorials/ReverseDebug/README.txt
Normal file
137
tutorials/ReverseDebug/README.txt
Normal file
@@ -0,0 +1,137 @@
|
||||
This is a tutorial/unittest for gdb's reverse debugging feature. It is a new
|
||||
feature that allows users to take a snapshot of the machine state, continue
|
||||
until a later stage of the program, then return to the previously recorded
|
||||
state and execute again. An ideal usage case is to help track down the reason
|
||||
why a memory location is clobbered.
|
||||
|
||||
In the sample below, the "clobber" function trashes a neighboring variable "p"
|
||||
on the stack next to the "values" variable, and the program will crash at
|
||||
line 42 when "p" is being dereferenced.
|
||||
|
||||
18 #include <stdio.h>
|
||||
19 #include <stdlib.h>
|
||||
20
|
||||
21 #define ARRAY_LENGTH 10
|
||||
22
|
||||
23 int flag;
|
||||
24
|
||||
25 void clobber(int *array, int size) {
|
||||
26 /* Make sure it clobbers something. */
|
||||
27 array[-1] = 0x123;
|
||||
28 array[size] = 0x123;
|
||||
29 }
|
||||
30
|
||||
31 int main(void) {
|
||||
32 int values[ARRAY_LENGTH];
|
||||
33 int *p = (int *) malloc(sizeof(int));
|
||||
34 *p = 10;
|
||||
35
|
||||
36 while (!flag) {
|
||||
37 sleep(1);
|
||||
38 }
|
||||
39
|
||||
40 /* Set a breakpint here: "b main.c:41" */
|
||||
41 clobber(values, ARRAY_LENGTH);
|
||||
42 printf("*p = %d\n", *p);
|
||||
43 free(p);
|
||||
44
|
||||
45 return 0;
|
||||
46 }
|
||||
|
||||
The test program can be built/installed on the device by doing:
|
||||
|
||||
> mmm development/tutorials/ReverseDebug
|
||||
> adb sync
|
||||
> adb shell reverse_debug
|
||||
|
||||
In another window the following command can be used to attach to the running
|
||||
program:
|
||||
|
||||
> gdbclient reverse_debug :5039 reverse_debug
|
||||
[1] 12802
|
||||
Attached; pid = 1842
|
||||
Listening on port 5039
|
||||
GNU gdb (GDB) 7.6
|
||||
Copyright (C) 2013 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 "--host=x86_64-linux-gnu --target=arm-linux-android".
|
||||
For bug reporting instructions, please see:
|
||||
<http://source.android.com/source/report-bugs.html>...
|
||||
Reading symbols from /usr/local/google/work/master/out/target/product/manta/symbols/system/bin/reverse_debug...done.
|
||||
Remote debugging from host 127.0.0.1
|
||||
nanosleep () at bionic/libc/arch-arm/syscalls/nanosleep.S:10
|
||||
10 mov r7, ip
|
||||
|
||||
====
|
||||
|
||||
Now set a breakpoint on line 41 and set flag to 1 so that the program can
|
||||
continue.
|
||||
|
||||
(gdb) b main.c:41
|
||||
Breakpoint 1 at 0xb6f174a8: file development/tutorials/ReverseDebug/main.c, line 41.
|
||||
(gdb) p flag=1
|
||||
$1 = 1
|
||||
(gdb) c
|
||||
Continuing.
|
||||
|
||||
====
|
||||
|
||||
Now try the new "record" command to take a snapshot of the machine state.
|
||||
|
||||
Breakpoint 1, main () at development/tutorials/ReverseDebug/main.c:41
|
||||
41 clobber(values, ARRAY_LENGTH);
|
||||
(gdb) record
|
||||
(gdb) c
|
||||
Continuing.
|
||||
|
||||
====
|
||||
|
||||
Now the program crashes as expected as "p" has been clobbered. The
|
||||
"reverse-continue" command will bring the program back to line 41 and let you
|
||||
replay each instruction from there.
|
||||
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
0xb6f174bc in main () at development/tutorials/ReverseDebug/main.c:42
|
||||
42 printf("*p = %d\n", *p);
|
||||
(gdb) reverse-continue
|
||||
Continuing.
|
||||
|
||||
No more reverse-execution history.
|
||||
main () at development/tutorials/ReverseDebug/main.c:41
|
||||
41 clobber(values, ARRAY_LENGTH);
|
||||
|
||||
|
||||
====
|
||||
|
||||
Now let's add a watch point at "&p" to hopefully catch the clobber on the spot:
|
||||
|
||||
(gdb) watch *(&p)
|
||||
Hardware watchpoint 2: *(&p)
|
||||
(gdb) c
|
||||
Continuing.
|
||||
Hardware watchpoint 2: *(&p)
|
||||
|
||||
====
|
||||
|
||||
And here it is:
|
||||
|
||||
Old value = (int *) 0xb728c020
|
||||
New value = (int *) 0x123
|
||||
0xb6f17440 in clobber (array=0xbebcaab0, size=10)
|
||||
at development/tutorials/ReverseDebug/main.c:28
|
||||
28 array[size] = 0x123;
|
||||
|
||||
|
||||
===============================
|
||||
|
||||
That said, reverse debugging on ARM is still in the infant stage. Currently
|
||||
(as of gdb 7.6) it only recognizes ARM instructions and will punt on all
|
||||
Thumb(2) instructions. To give it a try you will need to recompile your
|
||||
program in ARM mode. To do that you have to add the ".arm" suffix to the
|
||||
desired file in Android.mk:
|
||||
|
||||
LOCAL_SRC_FILES:= main.c.arm
|
||||
|
||||
46
tutorials/ReverseDebug/main.c
Normal file
46
tutorials/ReverseDebug/main.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARRAY_LENGTH 10
|
||||
|
||||
int flag;
|
||||
|
||||
void clobber(int *array, int size) {
|
||||
/* Make sure it clobbers something. */
|
||||
array[-1] = 0x123;
|
||||
array[size] = 0x123;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int values[ARRAY_LENGTH];
|
||||
int *p = (int *) malloc(sizeof(int));
|
||||
*p = 10;
|
||||
|
||||
while (!flag) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
/* Set a breakpint here: "b main.c:41" */
|
||||
clobber(values, ARRAY_LENGTH);
|
||||
printf("*p = %d\n", *p);
|
||||
free(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user