顯示具有 gdb 標籤的文章。 顯示所有文章
顯示具有 gdb 標籤的文章。 顯示所有文章

2015年6月1日 星期一

[Embedded] 利用 gdb script 實作 strcmp 函數

要在 gdb 內直接使用條件式中斷(Conditional breakpoint),例如:當某個字串出現時程式才進入中斷點,應該怎麼做呢?

1. 可以使用 commands 命令來設定條件式中斷
break foo
commands
if x>0
continue
else
printf "x is %d\n",x
end
end

2. 問題在於如何比較字串,以下整理網路上找到的幾種作法。若gdb版本較舊,則可能需要找尋其他方法。

方法一:使用 strcmp
(gdb) set $x = malloc(strlen("foobar") + 1)(gdb) call strcpy($x, "foobar")(gdb) break a_leg if strcmp(foo, $x) == 0

方法二:透過 python
可以直接使用下列函數 (Convenient functions) 
$_memeq(buf1buf2length)Returns one if the length bytes at the addresses given by buf1 and buf2 are equal. Otherwise it returns zero.  
$_regex(strregex)Returns one if the string str matches the regular expression regex. Otherwise it returns zero. The syntax of the regular expression is that specified by Python's regular expression support.  
$_streq(str1str2)Returns one if the strings str1 and str2 are equal. Otherwise it returns zero. 




也可以自行實作 strcmp
(gdb) define strcmp>py print cmp(gdb.execute("output $arg0", to_string=True).strip('"'), $arg1)>end(gdb) strcmp $x "hello"0

針對舊版本的 gdb,例如我所使用的 gdb 7.1,並不支援上述函數,因此需要自行實作一個 conevenient function,範例如下: 
py
class MyStrcmp (gdb.Function):
    """My Own Strcmp"""

    def __init__ (self):
        super (MyStrcmp, self).__init__ ("mystrcmp")

    def invoke (self, arg0, arg1):
        print "input '" + arg0.string() + "' and '" + arg1.string() + "'"
        if arg0.string() == arg1.string() :
            print "equal"
            return 0
        else:
            print "not equal"  
            return 1
MyStrcmp()
end
用法: 
print $mystrcmp("hello", "hello")

方法三:使用 gdb script 實作 strcmp
set var  $_isEq=0

# Yes! GDB_STRCMP, below, is a gdb function.
# Function that provides strcmp-like functionality for gdb script;
# this function will be used to match the password string provided in command line argument
# with the string argument of strcmp in program
define GDB_STRCMP
set var  $_i=0
set var  $_c1= *(unsigned char *) ($arg0 + $_i)
set var  $_c2= *(unsigned char *) ($arg1 + $_i)
while (  ($_c1 != 0x0) && ($_c2 != 0x0) && ($_c1 == $_c2) )

#printf "\n i=%d, addr1=%x(%d,%c), addr2=%x(%d,%c)", $_i, ($arg0 + $_i),$_c1, $_c1, ($arg1 + $_i), $_c2,$_c2
set  $_i++
set  $_c1= *(unsigned char *) ($arg0 + $_i)
set  $_c2= *(unsigned char *) ($arg1 + $_i)

#while end
end

if( $_c1 == $_c2)
set $_isEq=1
else
set $_isEq=0
end

#GDB_STRCMP end
end

Reference:

  1. https://sourceware.org/gdb/onlinedocs/gdb/Break-Commands.html
  2. http://stackoverflow.com/questions/13961368/conditional-breakpoint-using-strcmp-in-gdb-on-mac-os-x-conflicts-with-objectiv
  3. https://sourceware.org/gdb/current/onlinedocs/gdb/Convenience-Funs.html
  4. http://stackoverflow.com/questions/7423577/how-to-compare-a-stored-string-variable-in-gdb
  5. http://www.opensourceforu.com/2011/09/modify-function-return-value-hack-part-2/

2015年3月28日 星期六

[Embedded] 使用 gdbserver 時,出現 armv5te 警告訊息

問題描述:使用 gdbserver 追蹤程式時,target 為 armv6 架構,但卻出現 armv5te 的警告訊息。

問題原因:我所使用的 tool chain arm-2009q3,預設會假設 target 為 armv5te架構

解決方法:

1. 先登入 Target 端 console,確認 cpu info 

1 # cat /proc/cpuinfo
2 Processor : ARMv6-compatible processor rev 5 (v6l)
3 BogoMIPS : 526.25
4 Features : swp half fastmult edsp java
5 CPU implementer : 0x41
6 CPU architecture: 6TEJ
7 CPU variant : 0x1
8 CPU part : 0xb36
9 CPU revision : 5
10
11 Hardware : Coconut
12 Revision : 13ec3011
13 Serial : 0000000000000000

2. 確認目前 arm-none-linux-gnueabi-gcc 的預設架構

1 $ arm-none-linux-gnueabi-gcc -Q --help=target
2 The following options are target specific:
3 -falign-arrays [disabled]
4 -mabi=
5 -mabort-on-noreturn [disabled]
6 -mapcs [disabled]
7 -mapcs-float [disabled]
8 -mapcs-frame [disabled]
9 -mapcs-reentrant [disabled]
10 -mapcs-stack-check [disabled]
11 -march= armv5te
12 -marm [enabled]
13 -mbig-endian [disabled]
14 -mcallee-super-interworking [disabled]
15 -mcaller-super-interworking [disabled]
16 -mcirrus-fix-invalid-insns [disabled]
17 -mcpu=
18 -mfix-cortex-m3-ldrd [enabled]
19 -mfix-janus-2cc [disabled]
20 -mfloat-abi=
21 -mfp16-format=
22 -mfp=
23 -mfpe [disabled]
24 -mfpe=
25 -mfpu=
26 -mglibc [enabled]
27 -mhard-float [disabled]
28 -mlittle-endian [enabled]
29 -mlong-calls [disabled]
30 -mlow-irq-latency [disabled]
31 -mmarvell-div [disabled]
32 -mpic-register=
33 -mpoke-function-name [disabled]
34 -msched-prolog [enabled]
35 -msingle-pic-base [disabled]
36 -msoft-float [disabled]
37 -mstructure-size-boundary=
38 -mthumb [disabled]
39 -mthumb-interwork [enabled]
40 -mtp=
41 -mtpcs-frame [disabled]
42 -mtpcs-leaf-frame [disabled]
43 -mtune=
44 -muclibc [disabled]
45 -mvectorize-with-neon-quad [disabled]
46 -mword-relocations [disabled]
47 -mwords-little-endian [disabled]
很明顯,若使用預設值 armv5te進行編譯,則 arm 架構不符。
3.  如何確認現在正在使用的 gdbserver 其適用的arm架構呢?
$arm-none-linux-gnueabi-readelf -A ./gdbserver
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "5TE"
  Tag_CPU_arch: v5TE
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align8_needed: Yes
  Tag_ABI_align8_preserved: Yes, except leaf SP
  Tag_ABI_enum_size: int

4 因此在重新編譯 gdbserver 時應該要指定 armv6,舉例如下:
~/gdb/gdb-7.9/gdb/gdbserver$./configure --build=i686-pc-linux-gnu --host=arm-none-linux-gnueabi  --target=arm-none-linux-gnueabi CROSS_COMPILE=arm-none-linux-gnueabi- CFLAGS='-g -O2 -march=armv6  -mtune=arm1136j-s'
編譯方式可參考此篇 。是否正確編譯成功,可透過 readelf 來檢視,如下: 
&arm-none-linux-gnueabi-readelf -A ./gdbserver
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "6"
  Tag_CPU_arch: v6
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align8_needed: Yes
  Tag_ABI_align8_preserved: Yes, except leaf SP
  Tag_ABI_enum_size: int

5. 那麼 arm 架構不符會發生什麼問題呢?
主要是編譯成機器語言時,可能會使用不同的instruction set或call convention,可能造成執行時的錯誤。其中差異可以參考此篇討論
6. 編譯 gdb
編譯方式如下
$./configure --target=arm-none-linux-gnueabi
$ make 
不過這樣編譯出來的 gdb,在進行遠端除錯時,會出現以下錯誤訊息
"warning: Can not parse XML target description; XML support was disabled at compile time" 
手動安裝 expat,重新編譯gdb便可解決,步驟如下:
可從此處下載原始碼 http://sourceforge.net/projects/expat/files/latest/download
$ tar zxvf expat-2.1.0.tar.gz
$ cd expat-2.1.0
$ ./configure
$ make;make install 
另外支援 python script 會方便許多,因此我個人偏好使用下列這個編譯方式
$ sudo apt-get install python2.7-dev
$./configure --target=arm-none-linux-gnueabi --with-expat --with-python
$ make
註:若編譯的是 gdb-7.1,其 python 支援的功能是有限制的
http://stackoverflow.com/questions/8986589/how-to-get-output-from-gdb-execute-in-pythongdb-gdb-7-1

7. 若不使用 gdbserver,要直接編譯一個在 target system 執行的 gdb,需要先編譯 termcap,可參考下列設定

Build termcap 
./configure --build=i686-pc-linux-gnu --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf CROSS_COMPILE=arm-linux-gnueabihf- --prefix=/home/albert/tools/termcap
Build gdb 
./configure --build=i686-pc-linux-gnu --host=arm-none-linux-gnueabi --target=arm-none-linux-gnueabi CROSS_COMPILE=arm-none-linux-gnueabi- CFLAGS='-g -O2 -I/home/albert/tools/termcap/include' LDFLAGS='-static -L/home/albert/tools/termcap/lib' CPPFLAGS='-I/home/albert/tools/termcap/include'

Reference:
http://ftp.gnu.org/gnu/gdb/ 
https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
https://lists.debian.org/debian-arm/2011/11/msg00043.html
http://blog.csdn.net/a_ran/article/details/38404483
http://www.360doc.com/content/12/0312/23/532901_193884753.shtml
http://www.360doc.com/content/12/0312/23/532901_193884753.shtml
http://stackoverflow.com/questions/4381102/differences-between-arm-architectures-from-a-c-programmers-perspective
http://www.it.uom.gr/teaching/gcc_manuals/onlinedocs/gdb_35.html
http://lists.gnu.org/archive/html/bug-gnu-emacs/2001-11/msg00579.html




2015年3月6日 星期五

[Embedded] 使用 gdb 時,程式因為收到 SIGTRAP 而結束的解決方法

問題描述:使用 gdb 追蹤程式時,程式因為收到 SIGTRAP 而結束。

問題現象:執行程式時,gdb 與 gdbserver分別出現下列 warning,接著當程式執行到 breakpoint 時,gdb便自行結束。

2015年2月6日 星期五

[Embedded] GDB script -- check stack when stack corrupt

若使用 gdb 檢查 core dump 時,發現 stack corrupt,此時該如何看到正確的 stack trace 呢?

問題情況舉例如下:(使用 stackoverflow 的例子做說明)

Program received signal SIGSEGV, Segmentation fault.
0x00000002 in ?? ()
(gdb) bt
#0  0x00000002 in ?? ()
#1  0x00000001 in ?? ()
#2  0xbffff284 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

問題解決方式:(假設系統架構為 Linux 32-bit x86)

1. 首先必須先大概了解 Linux 作業系統內的虛擬記憶體配置
例如:
stack 會位於 0xBFxxxxxx 附近
text (程式碼) 會從 0x08048000 開始增加
因此 0xbffff284可能是正確的 stack位址,而 0x00000001 與 0x00000002 並非正確的 stack 位址,此時 stack 已經亂掉。
若對於 stack 使用有疑問,可以直接參考此範例。 

2. 以上述的錯誤位址為例,這個問題有可能因為呼叫function 時,指向了錯誤的 function pointer。
An indirect call instruction just pushes the PC after the call onto the stack and then sets the PC to the target value (bogus in this case), so if this is what happened, you can easily undo it by manually popping the PC off the stack. In 32-bit x86 code you just do:

(gdb) set $pc = *(void **)$sp
(gdb) set $sp = $sp + 4

3. 另外一個可能是正確的 stack 被覆蓋了。此時基本處理原則是將整個 stack 都尋找一遍,直到找到對應的程式進入點為止 (例如:main())。
例如: (gdb) x/256wa $sp 
其基本原理為從目前的 sp register 開始,每隔一個 word(4bytes),印出對應的位址,若有對應的 symbol 會一併列印,持續尋找 256 words。

4. 若想要將 stack 狀態寫入檔案,可以參考 Loda's blog 的 GDB 筆記,其基本原理與 x/256wa $sp 相同,不過產生出的 log 較方便閱讀。摘錄如下:
file executable_file_build_with_debug_flag
set solib-search-path builtin-symbol-library-file-path
set solib-absolute-prefix builtin-symbol-library-filepath-prefix
core core_dump_file
set print symbol-filename on
set logging file stack-out.txt
set logging on
set $stack_addr=$sp
printf "Start to decode tack\n"
set $i=0
while($i<256 br=""> printf "i:%ld stack_addr:%xh\n",$i,$stack_addr
print /a *(int *) $stack_addr
set $stack_addr = $stack_addr +4
set $i = $i + 1
end
printf "End\n"
set logging off

Reference:

2012年2月29日 星期三

[轉] 使用 Core Dump 找出問題


原文出處: http://blogger.org.cn/blog/more.asp?name=yach&id=22810

====
先看看我用的是什麼機器:

$ uname -a
Linux dev 2.4.21-9.30AXsmp #1 SMP Wed May 26 23:37:09 EDT 2004 i686 i686 i386 GNU/Linux

再看看預設的一些參數,注意core file size若是0,程序出錯?不會產生core文件了。

$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited

寫個簡單的程序,看看core文件是不是會被產生。