【打印調用棧】
(gdb) bt #0 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10 #1 0x401275ea in android::Looper::pollInner (this=this@entry=0x747fd3f0, timeoutMillis=<optimized out>, timeoutMillis@entry=85688516) at system/core/libutils/Looper.cpp:223 #2 0x40127814 in android::Looper::pollOnce (this=0x747fd3f0, timeoutMillis=85688516, outFd=outFd@entry=0x0, outEvents=outEvents@entry=0x0, outData=outData@entry=0x0) at system/core/libutils/Looper.cpp:191 #3 0x401d13dc in pollOnce (timeoutMillis=<optimized out>, this=<optimized out>) at system/core/include/utils/Looper.h:176 #4 android::NativeMessageQueue::pollOnce (this=0x747fef58, env=0x4151dfa8, timeoutMillis=<optimized out>) at frameworks/base/core/jni/android_os_MessageQueue.cpp:97 #5 0x4153d310 in dvmPlatformInvoke () at dalvik/vm/arch/arm/CallEABI.S:258 #6 0x4156d8de in dvmCallJNIMethod (args=0x6d5a5e18, pResult=0x4151f568, method=0x6d60e2d8, self=0x4151f558) at dalvik/vm/Jni.cpp:1159 #7 0x41546724 in dalvik_mterp () at dalvik/vm/mterp/out/InterpAsm-armv7-a-neon.S:16240
【切換到調用棧的第n層】
(gdb) f 11 #11 0x41587ff6 in Dalvik_java_lang_reflect_Method_invokeNative (args=<optimized out>, pResult=0x4151f568) at dalvik/vm/native/java_lang_reflect_Method.cpp:101 101 noAccessCheck);
【顯示匯編代碼】
(gdb) disassemble
Dump of assembler code for function Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*):
0x41587f7c <+0>: stmdb sp!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, r10, r11, lr}
0x41587f80 <+4>: add.w r4, r0, #12
0x41587f84 <+8>: ldmia.w r4, {r4, r8, r9}
0x41587f88 <+12>: mov r5, r0
0x41587f8a <+14>: mov r11, r1
0x41587f8c <+16>: ldr r6, [r0, #4]
0x41587f8e <+18>: ldr r7, [r0, #8]
0x41587f90 <+20>: ldr.w r10, [r0, #28]
0x41587f94 <+24>: ldr r1, [r5, #24]
0x41587f96 <+26>: mov r0, r4
0x41587f98 <+28>: bl 0x4158e828 <dvmSlotToMethod(ClassObject*, int)>
0x41587f9c <+32>: ldr r3, [r0, #4]
...
(gdb) disassemble 0x401b406c
Dump of assembler code for function _JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...):
0x401b4058 <+0>: push {r2, r3}
0x401b405a <+2>: push {r0, r1, r4, lr}
0x401b405c <+4>: add r3, sp, #16
0x401b405e <+6>: ldr r4, [r0, #0]
0x401b4060 <+8>: ldr.w r2, [r3], #4
0x401b4064 <+12>: ldr.w r4, [r4, #568] ; 0x238
0x401b4068 <+16>: str r3, [sp, #4]
0x401b406a <+18>: blx r4
0x401b406c <+20>: ldmia.w sp!, {r2, r3, r4, lr}
0x401b4070 <+24>: add sp, #8
0x401b4072 <+26>: bx lr
End of assembler dump.
【查看當前的寄存器值】
(gdb) info reg r0 0x0 0 r1 0x4151dfa8 1095884712 r2 0x10 16 r3 0x0 0 r4 0x4175c138 1098236216 r5 0x6d68eeb8 1835593400 r6 0x0 0 r7 0x42dc4350 1121731408 r8 0x42dc4278 1121731192 r9 0x416f12a8 1097798312 r10 0x0 0 r11 0x4151f568 1095890280 r12 0xbe88e2d8 3196642008 sp 0xbe88e6c0 0xbe88e6c0 lr 0x41587ff7 1096318967 pc 0x41587ff6 0x41587ff6 <Dalvik_java_lang_reflect_Method_invokeNative(u4 const*, JValue*)+122> cpsr 0x200f0030 537854000
【顯示當前進程的所有線程】
(gdb) info thread Id Target Id Frame 15 LWP 1992 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10 14 LWP 2076 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10 13 LWP 1815 __futex_syscall3 () at bionic/libc/arch-arm/bionic/futex_arm.S:39 12 LWP 1814 recvmsg () at bionic/libc/arch-arm/syscalls/recvmsg.S:9 11 LWP 1808 __futex_syscall3 () at bionic/libc/arch-arm/bionic/futex_arm.S:39 10 LWP 1817 __futex_syscall3 () at bionic/libc/arch-arm/bionic/futex_arm.S:39 9 LWP 1813 __rt_sigtimedwait () at bionic/libc/arch-arm/syscalls/__rt_sigtimedwait.S:10 8 LWP 1819 __futex_syscall3 () at bionic/libc/arch-arm/bionic/futex_arm.S:39 7 LWP 2062 __futex_syscall3 () at bionic/libc/arch-arm/bionic/futex_arm.S:39 6 LWP 1818 __futex_syscall3 () at bionic/libc/arch-arm/bionic/futex_arm.S:39 5 LWP 1826 __ioctl () at bionic/libc/arch-arm/syscalls/__ioctl.S:9 4 LWP 2320 __ioctl () at bionic/libc/arch-arm/syscalls/__ioctl.S:9 3 LWP 2210 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10 2 LWP 1824 __ioctl () at bionic/libc/arch-arm/syscalls/__ioctl.S:9 * 1 LWP 1804 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10
【切換線程】
(gdb) t 9 [Switching to thread 9 (LWP 1813)] #0 __rt_sigtimedwait () at bionic/libc/arch-arm/syscalls/__rt_sigtimedwait.S:10 10 mov r7, ip (gdb) bt #0 __rt_sigtimedwait () at bionic/libc/arch-arm/syscalls/__rt_sigtimedwait.S:10 #1 0x400b039c in sigwait (set=<optimized out>, sig=0x7194ad48) at bionic/libc/bionic/sigwait.cpp:43 #2 0x415716ca in signalCatcherThreadStart (arg=<optimized out>) at dalvik/vm/SignalCatcher.cpp:287 #3 0x41574176 in internalThreadStart (arg=0x747fd9d8) at dalvik/vm/Thread.cpp:1746 ...
【查看內存值】
(gdb) x /32wx 0x7194ad48 0x7194ad48: 0x00000004 0x6fbf3830 0x415dabd8 0x41573619 0x7194ad58: 0x41700880 0x42dc0768 0x00000005 0x00000001 0x7194ad68: 0x00000001 0x00000000 0x6fbf3830 0x747fd9d8 0x7194ad78: 0x415dabd8 0xbe88e598 0x747fd9d8 0x41574129 0x7194ad88: 0x7184d000 0x415db07c 0x400e92ec 0x41574177 0x7194ad98: 0x747fd9d8 0x00010002 0x747fd9f8 0x41700880 0x7194ada8: 0x7194add0 0x747f85a8 0x41574129 0x400aa1d4 0x7194adb8: 0x747fd9d8 0x747f85a8 0x7194add0 0x00000001 (gdb) x /20c 0xbe88eb48 0xbe88eb48: 47 '/' 115 's' 98 'b' 105 'i' 110 'n' 58 ':' 47 '/' 118 'v' 0xbe88eb50: 101 'e' 110 'n' 100 'd' 111 'o' 114 'r' 47 '/' 98 'b' 105 'i' 0xbe88eb58: 110 'n' 58 ':' 47 '/' 115 's'
【顯示符號】
(gdb) p *(Method*)0x6d682328
$1 = {clazz = 0x41755dc0, accessFlags = 9, methodIndex = 0, registersSize = 6, outsSize = 3, insSize = 1, name = 0x6f8c1862 <Address 0x6f8c1862 out of bounds>, prototype = {dexFile = 0x6d5aac48, protoIdx = 3750}, shorty =
0x6f88be67 <Address 0x6f88be67 out of bounds>, insns = 0x6f745d98, jniArgInfo = 0, nativeFunc = 0x0, fastJni = false, noRef = false, shouldTrace = false, registerMap = 0x71a557d8, inProfile = false}
【若干配置】
set print pretty on :結構體顯示的漂亮一些
set print union :設置顯示結構體時,是否顯式其內的聯合體數據。
set print vtbl :當此選項打開時,GDB將用比較規整的格式來顯示虛函數表時。其默認是關閉的。
例如:
(gdb) set print pretty on
(gdb) p *(Method*)0x6d682328
$2 = {
clazz = 0x41755dc0,
accessFlags = 9,
methodIndex = 0,
registersSize = 6,
outsSize = 3,
insSize = 1,
name = 0x6f8c1862 <Address 0x6f8c1862 out of bounds>,
prototype = {
dexFile = 0x6d5aac48,
protoIdx = 3750
},
shorty = 0x6f88be67 <Address 0x6f88be67 out of bounds>,
insns = 0x6f745d98,
jniArgInfo = 0,
nativeFunc = 0x0,
fastJni = false,
noRef = false,
shouldTrace = false,
registerMap = 0x71a557d8,
inProfile = false
}
(gdb) p *(art::ScopedObjectAccess *) 0xbe81e618 A syntax error in expression, near `) 0xbe81e618'.
(gdb) p *('art::ScopedObjectAccess' *) 0xbe81e618
$19 = {
<art::ScopedObjectAccessUnchecked> = {
<art::ScopedObjectAccessAlreadyRunnable> = {
self_ = 0xb4f07800,
env_ = 0xb4f512b0,
vm_ = 0xb4f5c280
},
members of art::ScopedObjectAccessUnchecked:
tsc_ = {
self_ = 0xb4f07800,
thread_state_ = art::kRunnable,
old_thread_state_ = art::kNative,\
expected_has_no_thread_ = false
}
}, <No data fields>}
(gdb) p &(('art::ScopedObjectAccess' *)0)->tsc_.expected_has_no_thread_
$26 = (const bool *) 0x18
(gdb) p &(('art::ScopedObjectAccess' *)0)->env_
$27 = (art::JNIEnvExt * const *) 0x4
(gdb) p &((struct task_struct *)0)->prio
$1 = (int *) 0x30
【如何獲取類的大小】
(gdb) p (('art::ScopedObjectAccess' *)0)+1
$33 = (art::ScopedObjectAccess *) 0x1c
【設置代碼搜索路徑】
(gdb) directory ~/disk/android/ Source directories searched: /home/disk/android:$cdir:$cwd
(gdb) list 67 } 68 69 // Uncompress an encoded reference from its bit representation. 70 MirrorType* UnCompress() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 71 uintptr_t as_bits = kPoisonReferences ? -reference_ : reference_; 72 return reinterpret_cast<MirrorType*>(as_bits); 73 } 74 75 friend class Object; 76
【查找內存值】
(gdb) find /w /20 0x41f7f0, 0x41f8f0, 0x3f800000
0x41f7f0~0x41f8f0范圍內的內存中,查詢0x3f800000,步長為word,最多查找20個。
【打印數組】
(gdb) p je_arenas
$0 = (arena_t **) 0x7f93f0a280
(gdb) p * (arena_t **) 0x7f93f0a280@10
$1 = {0x7f93e02200, 0x7f93f12280, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
編譯程序時需要加上-g,之后才能用gdb進行調試:gcc -g main.c -o main
gdb中命令:
回車鍵:重復上一命令
(gdb)help:查看命令幫助,具體命令查詢在gdb中輸入help + 命令,簡寫h
(gdb)run:重新開始運行文件(run-text:加載文本文件,run-bin:加載二進制文件),簡寫r
(gdb)start:單步執行,運行程序,停在第一執行語句
(gdb)list:查看原代碼(list-n,從第n行開始查看代碼。list+ 函數名:查看具體函數),簡寫l
(gdb)set:設置變量的值
(gdb)next:單步調試(逐過程,函數直接執行),簡寫n
(gdb)step:單步調試(逐語句:跳入自定義函數內部執行),簡寫s
(gdb)backtrace:查看函數的調用的棧幀和層級關系,簡寫bt
(gdb)frame:切換函數的棧幀,簡寫f
(gdb)info:查看函數內部局部變量的數值,簡寫i
(gdb)finish:結束當前函數,返回到函數調用點
(gdb)continue:繼續運行,簡寫c
(gdb)print:打印值及地址,簡寫p
(gdb)quit:退出gdb,簡寫q
(gdb)break+num:在第num行設置斷點,簡寫b
(gdb)info breakpoints:查看當前設置的所有斷點
(gdb)delete breakpoints num:刪除第num個斷點,簡寫d
(gdb)display:追蹤查看具體變量值
(gdb)undisplay:取消追蹤觀察變量
(gdb)watch:被設置觀察點的變量發生修改時,打印顯示
(gdb)i watch:顯示觀察點
(gdb)enable breakpoints:啟用斷點
(gdb)disable breakpoints:禁用斷點
(gdb)x:查看內存x/20xw 顯示20個單元,16進制,4字節每單元
(gdb)run argv[1] argv[2]:調試時命令行傳參
(gdb)set follow-fork-mode child#Makefile項目管理:選擇跟蹤父子進程(fork())
core文件:先用$ ulimit -c 1024 開啟core,當程序出錯會自動生成core文件。調試時 gdb a.out core
使用gdb添加斷點的幾種方式
設置斷點有很多方式。下面我們舉例說明下常用的幾種方式。
通過行號設置斷點
格式:
break [行號]
break 行號,斷點設置在該行開始處,注意:該行代碼未被執行
如果你的程序是用c或者c++寫的,那么你可以使用“文件名:行號”的形式設置斷點。示例如下:
//test.c #include <stdio.h> void judge_sd(int num){ if ((num & 1) == 0){ printf("%d is even\n",num); return; }else{ printf("%d is odd\n",num); return; } } int main(int argc, char const *argv[]){ judge_sd(0); judge_sd(1); judge_sd(4); return 0; }
編譯:
gcc -g test.c -o test
- 1

gdb test

break 文件名 : 行號,適用於有多個源文件的情況。
示例中的(gdb) b test.c:18是設置了斷點。斷點的位置是test.c文件的18行。使用r命令執行腳本時,當運行到18行時就會暫停。注意:該行代碼未被執行
通過函數設置斷點
格式:
break [函數名]
break 函數名,斷點設置在該函數的開始處,斷點所在行未被執行:
同樣可以將斷點設置在函數處:
b judge_sd

設置條件斷點
如果按上面的方法設置斷點后,每次執行到斷點位置都會暫停。有時候非常討厭。我們只想在指定條件下才暫停。這時候根據條件設置斷點就有了用武之地。設置條件斷點的形式,就是在設置斷點的基本形式后面增加 if條件。示例如下:
break test.c:6 if num>0
- 1

當在num>0時,程序將會在第6行斷住。
查看斷點
語法:
info breakpoints
可以使用info breakpoints查看斷點的情況。包含都設置了那些斷點,斷點被命中的次數等信息。示例如下:
它將會列出所有已設置的斷點,每一個斷點都有一個標號,用來代表這個斷點。
刪除斷點
語法:
delete breakpoint
對於無用的斷點我們可以刪除。刪除的命令格式為 delete breakpoint 斷點編號。info breakpoint命令顯示結果中的num列就是編號。刪除斷點的示例如下:

查看源碼
斷點設置完后,當程序運行到斷點處就會暫停。暫停的時候,我們可以查看斷點附近的代碼。查看代碼的子命令是list,縮寫形式為l。

指定行號查看代碼
語法:
list first,last
例如,要列出6到21行之間的源碼:

列出指定文件的源碼
前面執行l命令時,默認列出test.c的源碼,如果想要看指定文件的源碼呢?可以
list 【文件名加行號或函數名】

總結
本文介紹了GDB調試中的斷點設置、源碼查看。斷點設置可以便於我們后期觀察變量,堆棧等信息,為進一步的定位與調試做准備。源碼查看可以通過指定行號或者方法名來查看相關代碼。
1. 普通斷點
根據代碼行數設置斷點是最常見的一種方式,在debug程序運行前就可以進行斷點的配置。如:
(gdb) b src/main.cpp:127
當程序執行到main.cpp文件的第127行時就會出發斷點。
2. 條件斷點
顧名思義,這種斷點是當滿足一定條件時才會觸發,比較適合進行異常排查。設置方式(gdb)break line-or-function if (condition), 如:
(gdb) b src/main.cpp:127 if cnt==10
3. 數據斷點
就是根據地址來進行設置斷點,只能是在debug程序運行之后設置,因為只有運行后,你才能很方便地獲知變量的地址。當該地址上的內容發生改變時就會觸發斷點。
設置數據斷點有兩種方式,一種是直接指出地址值,如:
(gdb) b *0x400522
注意必須加*號。而獲取地址值的方法是,先設置普通斷點,在斷點處print &變量名 就能獲取該變量的地址。
另一種當然就是直接設置變量名了,如:
(gdb) b &變量名
4. 函數斷點
這種斷點是當程序執行到某個程序時就會觸發斷點。設置方式如:
(gdb) b funcName
但是函數斷點並不是對所有函數都有效,比如優化后的靜態函數和inline函數等,可能就無法觸發斷點。
5. 監視
設置監視也必須是在程序運行后才行。如:
(gdb) watch *地址 # 當地址所指內容發送變化時斷點 (gdb) watch var #當var值變化時,斷點 (gdb) watch (condition) #當條件符合時,斷點
監視也被稱為硬件斷點。可以監測棧變量和堆變量值的變化,當被監測變量值發生變化時,程序被停住。
