GDB – Cheatsheet : Những lệnh hay dùng của GDB
Mình là fan của gdb, mình đã sử dụng nó cho hầu hết các project trên linux của mình, tuy chỉ là command based nhưng rất hữu dụng nếu sử dụng hợp lý, ngoài là công cụ debug nếu sử dụng đúng gdb là công cụ reverse code rất hữu hiệu. Dò trên 4rum chưa thấy có bài nào viết, mình xin chia xẻ chút kinh nghiệm.
Do thời gian có hạn, nên mình sẽ chỉ viết những lệnh mình thấy hữu dụng nhất mà mình cảm nhận quá trình làm việc. Bạn nào biết lệnh nào “lợi hại” xin post chung vào topic này, mình sẽ update.
Quy định trong bài viết :
$ xyz : lệnh xyz được ví dụ khi thực hiện trên shell (bash,sh,ksh...). Để thử nghiệm, type xyz và nhấn ENTER
(gdb) zyx : lệnh zyx được ví dụ khi thực hiện bên trong GDB ( sau khi khởi động ). Để thử nghiệm, type zyx trong gdb và nhấn ENTER. ( Một số lệnh đòi hỏi gdb phải attach vào chương trình trước xin xem ở dưới )
1) Khởi động gdb
a) Cách 1:
gdb [--args] path_đến_program : khởi động gdb và set file cần debug ngay lập tức. Nêu cần khai báo tham số cho program thì sử dụng --args ở phía trước gdb
Code:
$ gdb helloworld
$ gdb ls
$ gdb --arg /bin/ls –al
b) Cách 2:
gdb : khởi động gdb không dùng tham số gì cả, bạn sẽ vào trong phần làm việc của gdb.
file [path đến program]: gõ lệnh này trong phần làm việc của gdb để chọn program cần debug.
Code:
$gdb
(gdb) file ls
Lưu ý cách 2 này bạn không thể khai báo tham số trước cho chương trình. ( Xem tiếp để biết làm cách nào add tham số. )
*** Để thoát khỏi gdb :
(gdb) quit
2) Kích hoạt chương trình:
run [args] : kích hoạt chương trình đang được “để ý” bởi gdb. [args] là tham số cần để chương trình chạy
Code:
(gdb) File ls
(gdb) Run –al
3) Xem code của chương trình
Để xem được source code của chương trình ngay trong gdb, bạn phải compile chương trình bằng cách thêm tham số debug : -g để compiler sinh ra debugging information, tiện cho việc debug hiệu quả. Xem thêm ở đây :
http://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html Code:
$ gcc –g –gdb –o xxx xxx.c
Sau đó trong gdb bạn có thể sử dụng lệnh "list" để xem source code của chương trình đang debug:
list [File:]line_number : xem code tại 1 dòng xác định, ( trong trường hợp có nhiều file thêm vào thông số [File:].
list [File:]Function : tương tự như trên nhưng xem tại điểm bắt đầu của hàm Funtion.
list : nếu không có tham số nào thì list sẽ cho xem source vị trí hiện tại đang debug. Nếu gõ liên tiếp sẽ cho xem các dòng tiếp sau đó.
Trong trường hợp bạn muốn debug 1 file binary mà không có source code. Sử dụng:
disassemble FUNC
Code:
(gdb) disassemble main
disassemble MEM1 MEM2: disassemble từ memory address MEM1 đến memory address MEM2
Code:
(gdb) disassemble 0xbfffbbbb 0xbfffcccc
*** Lưu ý assembly mà gdb tại ra là dạng AT&T, i.e destination đứng sau source:
mov 0x0 %eax <-- eax = 0
4) Break Point và Watch Point:
- BreakPoint:
Khi chạy chương trình, bạn muốn chương trình của bạn dừng lại ở một số đoạn nào để debug. Bạn sử dụng lệnh: break. Cú pháp tương tự như lệnh list
break [File:]line_number
Code:
(gdb) break main.c:200
break [File:]Function
Code:
(gdb) break main.c:main
break *MEM : dừng lại khi execute đến memory address MEM ( hữu dụng khi làm việc với binary file)
Code:
(gdb) break * 0x08151c24
- Watch Point:
Sử dụng watch point khi muốn theo dõi 1 variable / expression, dừng chương trình khi nó thay đổi.
Code:
(gdb) watch i
(gdb) watch src.data == des.data
5) Để xem các bạn đã có những breakpoints / watchpoints nào :
info breakpoints
Để xóa 1 breakpoint/watchpoint:
delete breakp_id/watch_id ( xem id bằng lệnh info )
Disable/Enable 1 breakpoint/watchpoint:
disable breakpoints [breakp_id] ( nếu không đề cập breakp_id thì toàn bộ sẽ bị disable )
enable breakpoints [breakp_id] ( ngược lại với disable )
6) Condition: Bạn có thể thêm condition cho breakpoint/watchpoint. Khi đó chương trình sẽ chỉ dừng lại ở vị trí đã set nếu như condition của bạn có giá trị true. Cú pháp:
Condition breakp_id / watch_id expression
Code:
(gdb) condition 1 x==y && x==999( x và y là variable của chương trình )
7) Program flow : sau khi break bạn có thể bắt gdb execute từng dòng code theo program của mình
step over : next
step in : step
continue : continue
Nếu execute theo instruction:
step over: nexti
step in: stepi
Để xem mình đang ở đâu trong program, được gọi bởi function nào :
where
backtrace
Code:
Program received signal SIGINT, Interrupt.
0xb75ebc32 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
(gdb) where
#0 0xb75ebc32 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1 0xb756c1f3 in __read_nocancel () from /lib/tls/libc.so.6
#2 0x080b2c0c in rl_getc ()
#3 0x080b2bcb in rl_read_key ()
#4 0x080a3a08 in readline_internal_char ()
#5 0x080a3bc5 in readline_internal_char ()
#6 0x080a3bf0 in readline_internal_char ()
#7 0x080a378a in readline ()
#8 0x0805db45 in yy_input_name ()
#9 0x08082ad0 in termination_unwind_protect ()
= )) có ai biết mình đang trace cái j không ?
Xem và cập nhật giá trị các biến, thanh ghi và bộ nhớ :
Để xem giá trị các biến : sử dụng print variable
Code:
(gdb) print i
(gdb) print inst.data
Để xem giá trị ô nhớ : x[/[cout][format][size]] memory
(gdb) x 0x12345678
(gdb) x/20 0x12345678 : xem 20 ô liên tiếp bắt đầu từ 0x12345678
(gdb) x/20xb 0x12345678 : xem 20 ô liên tiếp dưới dạng hex và in ra từng byte.
[format]: o(octal), x(hex), d(decimal), u(unsigned decimal), t(binary), f(float), a(address), i(instruction), c(char), s(string)
[size]: b(byte,1 byte), h(halfword, 2 bytes), w(word, 4 bytes), g(giant, 8 bytes)
Để xem thanh ghi: Tương tự xem ô nhớ, thay memory bằng thanh ghi:
Code:
(gdb) x $eax
(gdb) x $eip
Hoặc sử dụng lệnh :
info register [REG]
Code:
(gdb) info register eax
Để cập nhật/ chỉnh sửa các giá trị :
set destination = something
(gdb) set $eax = 1
(gdb) set *(0xbfffdddd) = “windak”
9) Một số tip khác khi sử dụng :
- Shortcut :
Khi sử dụng thành thạo và quen với các lệnh của gdb, bạn có thể bắt đầu sử dụng các lệnh tắt. Gdb cho phép shortcut command bằng cách viết phần prefix của command đó.
(gdb) r <=> (gdb) ru <=> (gdb) run
(gdb) b <=> (gdb) break
(gdb) disass <=> (gdb) disassemble ( lưu ý số prefix phải đủ dài để gdb xác định là lệnh nào)
(gdb) i b <=> (gdb) info break
- Debug program đang chạy ( process ):
gdb [prog] [pid] ( pid = process id, xem thêm lệnh “ps” của linux )
- Xem hướng dẫn của một lệnh
help [command]
(gdb) help break
(gdb) help next
- Sử dụng liên tiếp 1 lệnh
Nhấn Enter trong gdb nếu bạn muốn gdb tiếp tục thực hiện lệnh phía trước. Hữu dụng khi xài chung với "next","nexti","step","stepi","list".
- Thực hiện một số command khi chương trình dừng ở break:
command breakp_id/watch_id
Code:
(gdb) br main
(gdb) command 1
> x $eax
> end
(gdb)
Trên là một số kiến thức cơ bản của gdb mà mình thu thập, khi viết bài không khỏi sai sót mong mọi người cùng đóng góp để hoàn thiện.
Một tài liệu advance nếu bạn hứng thú: Using GNU's GDB Debugger:
http://dirac.org/linux/gdb/ References:
$gdb --help
(gdb) help