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