2015年12月24日 星期四

重新安裝 Mac OS

這個星期要把舊 Mac 搬回家給爸爸用了,將處理舊 Mac 的過程作一記錄

2015年11月3日 星期二

[Embedded] Arduino RFID 模組

前陣子到光華商場買了一個 RFID 模組,今晚比較有空,便來玩玩看,作個記錄。

測試設備
  • Arduino UNO 
  • RFID-RC522,一組$280,含兩個 RFID Card 和 RFID Reader

在 iOS 設備上使用 gSoap

本篇以 WSDiscovery 為例,說明如何在 iOS 上使用 gSOAP ,
使用的軟體版本為  gSOAP  2.8.19 與 XCODE  6.4

1. 取得軟體
gSOAP 可從 sourceforge 下載,  xcode 可從 Mac 內建的 AppStore取得。

2. 用 gSOAP 產生需要的程式碼,詳細作法可參考此篇文章


3. 可選擇使用 iOS plugin,或自行實作網路介面
iOS plugin 利用 iOS 的 NSURL 與 NSMutableURLRequest 來實作傳送與接收 HTTP 層的資料,使用範例如下: 
 #import "gsoapios.h"
struct soap *soap = soap_new();
soap_register(soap, soap_ios); // Register the iOS plugin
 ...
soap_end(soap);  // clean up allocated temporaries
soap_destroy(soap); // Free soap context 
iOS plugin 的方法簡介
  • 設定 Cache Policy
soap_ios_setchacepolicy(soap, NSURLRequestReturnCacheDataElseLoad); 
  • 設定timeout
soap_ios_settimeoutinterval(soap, 30.0); 
  • 設定帳號密碼
soap->userid = "someone";
soap->passwd = "somepass";
   
4. 以wsdiscovery 為例,實作方式摘錄如下
a.直接取得 wsdiscovery 程式碼
git clone https://github.com/alb423/wsdiscovery
b.開啟 xcode, 新增一個 project, 將 wsdiscovery 目錄內的檔案都新增至 Project (main.c除外) 
c. 新增 wsdiscovery_api.m,參考 main.c 進行小量修改 
d. 開始編譯。此時會出現幾種錯誤,主要其解決方式如下
d1. 找不到 NSString,在 gsoapios.h 加入include file 即可,如下:
#import <UIKit\UIKit.h>
d2. 找不到 DLog,在 gsoapios.h 自行定義即可,如下:
#ifdef DEBUG
#define DLog NSLog
#else
#define DLog(X, ...) ;;;
#endif         
d3. ARC (Automatic Reference Counting), 
可設定 gsoapios.m 不使用 ARC,設定方式為 Target -> Build Phases -> Compile Sources -> 選擇 gsoapios.m,輸入 -fno-objc-arc即可。如下圖

   
d4. "ARC forbids Objective-C objects in struct"
將 GSoapiOSURLData *url_data;
改為 __unsafe_unretained GSoapiOSURLData *url_data;
 
5. 本範例直接操作 socket,並不需要 HTTP,因此沒有用到 iOS plugin。接下來我將會在 iOS 上使用 gSOAP 與 ONVIF command 結合,並藉由這個範例來測試 iOS plugin。

註1: 範例程式碼可從 https://github.com/alb423/wsdiscovery 下載
註2: 針對 ARC 錯誤,也可以請 Xcode 自動將程式碼轉換成 ARC。作法是 Edit -> Convert -> Convert to Objective-C ARC...,可參考此篇文章 http://onevcat.com/2012/06/arc-hand-by-hand/

2015年9月24日 星期四

[OpenCV] Cross compilation for ARM based Linux systems (static)

本篇記錄編譯 OpenCV (static) 的過程。

2015年8月31日 星期一

[OpenCV] 鏡頭校正 Calibration

OpenCV 已經內建鏡頭校正的範例程式,並且提供了許多範例圖片,3.0版本更針對魚眼鏡頭提供了新的函數。這些功能還挺好玩的,以下作一記錄

2015年8月25日 星期二

[OpenCV] OpenCV for iOS

對於 iOS 上如何使用 OpenCV,docs.opencv.org 提供了很多參考文件。
以下對自己的測試過程,作一記錄

1. 可以直接取得 OpenCV framework,或是自行編譯 OpenCV
可至此處 http://sourceforge.net/projects/opencvlibrary/files/opencv-ios/ 直接下載。
本次測試,我選擇自行編譯,步驟如下

[OpenCV]  FAQ

此處收集自己使用 OpenCV時遇到的問題與解決方法


1. 沒有 link zlib,錯誤訊息如下
persistence.cpp:(.text.cvOpenFileStorage+0x4a8): undefined reference to `gzrewind'
persistence.cpp:(.text.cvOpenFileStorage+0x844): undefined reference to `gzopen'
persistence.cpp:(.text.cvOpenFileStorage+0xa98): undefined reference to `gzclose'
persistence.cpp:(.text.cvOpenFileStorage+0xcee): undefined reference to `gzgets' 
解法: 自行編譯compile zlib 或是找到可用的 zlib,之後加上 -lzlib 再次編譯即可

2015年8月19日 星期三

我的飛行器 -- 第一次飛行

第一次飛行,選擇住家旁邊的國小,還不太懂的怎樣控制四軸的我,玩了十多分鐘,就墜機十多次,結果最後飛機撞上操場旁的小小山丘,飛機機架就斷了.... 還好網路上各式各樣的零件都有賣,這個斷掉的機架只要台幣 55 。


我想是因為自己的操控技巧太差了,因此便找了dkck幫我接上nRF24L01高頻頭,並買了 jj-1000p 來練練手感。


練了之後,才發現飛四軸真的是需要多多練習的,第一次就直接拿著萬把元的實機練習的我,真的是太大膽了。我連500元的小小四軸都飛不好呢.... 還是先練練小台的再說。


2015年8月5日 星期三

[OpenCV] How to install OpenCV in Mac OS

安裝過程摘要

1. download latest opencv package from  http://opencv.org/
$ wget https://github.com/Itseez/opencv/archive/3.0.0.zip

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年4月27日 星期一

[Embedded] 如何替換系統內預設的 memcpy 函數

最近使用 perf 替手邊的嵌入式系統進行效能分析,發現系統內最常被用到的函數是 memcpy(),若能夠優化此函數,應該可以改善系統效能吧。以下記錄整個實驗過程。

1. 系統效能分析
編譯perf的方法可參考此篇文章。使用 "perf top" 可以得知觀察系統當前的狀態,找到最耗時的函數。 
"perf top"原文說明如下:

The default sampling event is cycles and default order is descending number of samples per symbol, thus perf top shows the functions where most of the time is spent. By default, perf top operates in processor-wide mode, monitoring all online CPUs at both user and kernel levels. It is possible to monitor only a subset of the CPUS using the -C option.
下圖為"perf top"的執行結果,由圖中可得知 libc-2.10.1.so 內的 memcpy 函數是整個系統最耗時的部分,因此我將針對此函數進行分析,評估是否有優化的空間。

2. memcpy 函數分析
首先需要先檢視 libc-2.10.1對memcpy的實作方式,glibc 原始碼可至 http://ftp.gnu.org/gnu/glibc/ 下載。我分別下載了 libc-2.10.1 和 libc-2.21 的程式碼並進行比較。其主要差別在於libc-2.10.1使用C語言撰寫,而 libc-2.21將memcpy則會使用ARM的組合語言。 
  • 比較 glibc-2.10.1\string\memcpy.c 與 glibc-2.21\string\memcpy.c,其內容幾乎一樣。 
  • 但 glibc-2.21 針對 memcpy 新增了 ARM 的組語版本 (\glibc-2.21\sysdeps\arm\memcpy.S),當編譯ARM版本的 libc 時,便會選擇編譯組語版本的 memcpy。 
合理的推論,在 ARM 架構下, \arm\memcpy.S 的運作效能應該優於 \string\memcpy.c

3. 如何替換 libc 內的 memcpy
為了簡單,我並沒有使用 glibc-2.21 的 memcpy,我直接從 android source code中取出對應的 memcpy.S,用來練習置換 libc memcpy,原始程式可至 github 取得。 
方法一:直接 link 自行改寫的 memcpy library,用法如下:
$(CC) memcpy_test.o memcpy.o -o memcpy_test
$ arm-none-linux-gnueabi-readelf -s ./memcpy_test
  110: 00008520     0 FUNC    GLOBAL DEFAULT   12 memcpy
  125: 000083f0     0 FUNC    GLOBAL DEFAULT  UND malloc@@GLIBC_2.4 
方法二:透過設定 LD_PRELOAD 可切換動態連結時所尋找的 library 順序
$(CC) memcpy_test.o  -o memcpy_test
$ arm-none-linux-gnueabi-readelf -s ./memcpy_test
  104: 000083f8     0 FUNC    GLOBAL DEFAULT  UND memcpy@@GLIBC_2.4
  110: 00008404     0 FUNC    GLOBAL DEFAULT  UND malloc@@GLIBC_2.4 
$ export LD_PRELOAD=/tmp/test/mem_practice/libmymemcpy.so
$ ./memcpy_test  (使用自行編譯的 memcpy) 
$ export LD_PRELOAD=
$ ./memcpy_test  (使用 libc 的 memcpy)
可透過下列命令切換不同的 memcpy 並測試效能
$ export LD_PRELOAD=/tmp/test/mem_practice/libmymemcpy.so
$ ./perf bench mem all 
$ export LD_PRELOAD=
$ ./perf bench mem all 
4. 針對整個系統,更換 user space 所使用的 memcpy
若確定修改過後的 memcpy library 效能的確較佳,則可以修改 /etc/ld.so.preload,讓系統每次在作 dynamic link 時,總是先尋找自行撰寫的 memcpy library. 
ld.so.preload 的內容舉例如下:
/lib/libmymemcpy.so

參考資料
  1. http://stackoverflow.com/questions/27171485/various-glibc-and-linux-kernel-versions-compatibility
  2. http://stackoverflow.com/questions/9107259/how-to-replace-c-standard-library-functioin
  3. http://stackoverflow.com/questions/426230/what-is-the-ld-preload-trick
  4. http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
  5. https://perf.wiki.kernel.org/index.php/Tutorial

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年3月2日 星期一

[Embedded] 在 ARM in Linux 編譯 perf

要改善系統效能,首先必須有個量測系統效能的工具,本篇紀錄在 ARM in Linux 如何手動編譯 perf 。

摘錄網路上對 perf 的說明如下:

perf (sometimes called "Perf Events"or perf tools, originally "Performance Counters for Linux", PCL) is a performance analyzing tool in Linux, available from Linux kernel version 2.6.31.

it can instrument CPU performance counters, tracepoints, kprobes, and uprobes (dynamic tracing). It is capable of lightweight profiling. It is also included in the Linux kernel, under tools/perf, and is frequently updated and enhanced.

perf 的使用範例可以參考 IBM提供的文章

2015年2月20日 星期五

[Embedded] 一個練習組合語言的小遊戲 -- Defusing bomb (part 2)

遊戲說明請參考  http://wiki.csie.ncku.edu.tw/embedded/Lab34


以下記錄自己的解答方式。本篇僅紀錄 part2 的解法,透過此練習可學得如何利用 stack overflow 來執行 shellcode。

[Embedded] 一個練習組合語言的小遊戲 -- Defusing bomb (part 1)

此遊戲的設計目的是要讓使用者學會利用 gdb 與 objdump 分析執行檔,並學習 hack 程式!!!! 遊戲說明請參考  http://wiki.csie.ncku.edu.tw/embedded/Lab34

以下記錄自己的解答方式。本篇僅紀錄 part1 的解法,簡單來說就是使用gdb找出正確輸入值,避免程式進入 explode_bomb()。

2015年2月7日 星期六

[Embedded] GDB script -- generate a basic report per core file

wikibook 針對 core dump 使用,提供了幾個有用的 script,其中有個自動產生報表的方式對我幫助很大。摘錄如下:


#!/bin/bash

#
# A script to extract core-file informations
#


if [ $# -ne 1 ]
then
echo "Usage: `basename $0` "
exit -1
else
binimg=$1
fi


# Today and yesterdays cores
cores=`find . -name '*.core' -mtime -1`

#cores=`find . -name '*.core'`


for core in $cores
do
gdblogfile="$core-gdb.log"
rm $gdblogfile

bininfo=`ls -l $binimg`
coreinfo=`ls -l $core`

gdb -batch \
-ex "set logging file $gdblogfile" \
-ex "set logging on" \
-ex "set pagination off" \
-ex "printf \"**\n** Process info for $binimg - $core \n** Generated `date`\n\"" \
-ex "printf \"**\n** $bininfo \n** $coreinfo\n**\n\"" \
-ex "file $binimg" \
-ex "core-file $core" \
-ex "bt" \
-ex "info proc" \
-ex "printf \"*\n* Libraries \n*\n\"" \
-ex "info sharedlib" \
-ex "printf \"*\n* Memory map \n*\n\"" \
-ex "info target" \
-ex "printf \"*\n* Registers \n*\n\"" \
-ex "info registers" \
-ex "printf \"*\n* Current instructions \n*\n\"" -ex "x/16i \$pc" \
-ex "printf \"*\n* Threads (full) \n*\n\"" \
-ex "info threads" \
-ex "bt" \
-ex "thread apply all bt full" \
-ex "printf \"*\n* Threads (basic) \n*\n\"" \
-ex "info threads" \
-ex "thread apply all bt" \
-ex "printf \"*\n* Done \n*\n\"" \
-ex "quit"
done

Reference:
http://en.m.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Core_files

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:

[Embedded] GDB script -- check deadlock caused by mutex

Gdb scripts can be used to fix bugs easily. So I collect some gdb script here as reference.
The first script is used to find the deadlock caused by mutex misuse.

Reference : Debug Hacks

1. For example: debug.cmd
set pagination offset logging file debug.log
set logging overwrite
set logging on
start
set $addr1 = pthread_mutex_lock
set $addr2 = pthread_mutex_unlock
b *$addr1
b *$addr2
while 1
   c
   if $pc != $addr1 & $pc != $addr2
      quit
   end
   printf "## addr : %08x\n", *(int *)($esp+4)
   bt
end 
NOTE: when you press ctrl+c, this script will quit.

2. Usage
$ gdb ./a.out -x debug.cmd

2015年1月24日 星期六

[Embedded] Why no core dump after segmentation fault?

1. Follow below command to set core dump generated in embedded Linux.
$ ulimit -c 1024
$ echo '/tmp/core_%e.%p' | tee /proc/sys/kernel/core_pattern

2. Why no core dump?
  • no write access to the directory 
  • use "ls" to check
  • the program changes the working directory 
  • how to check??
  • look for the core in other places too 
  • use "sysctl -a | grep core_pattern" to check
  • disk is full 
  • use "df ." to check
  • most Unix systems do not allow a setuid process to dump core 
  • use "cat /proc/sys/fs/suid_dumpable" to check,  
  • use "echo 1 > /proc/sys/fs/suid_dumpable" to change setting 
  • ulimit is set in one shell and the program is started in a different shell or environment
  • check /proc/pid/environ for current shell
  • note that only the program executed after "ulimit -c 1024" can generate core

3. We can use "kill -ABRT  pid_of_process" to generate core manually.

4. Check /proc/pid/limits for system limit
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            8388608              unlimited            bytes
Max core file size        0                    unlimited            bytesMax resident set          unlimited            unlimited            bytes
Max processes             748                  748                  processes
Max open files            1024                 1024                 files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       748                  748                  signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us

Reference:
  1. http://stackoverflow.com/questions/15272817/segmentation-fault-no-core-dump
  2. http://www.idimmu.net/2013/06/21/enable-linux-core-dump/
  3. http://www.gnu.org/software/bash/manual/bashref.html#Bourne-Shell-Builtins
  4. http://blog.csdn.net/pro_or_gram/article/details/15813879
  5. http://linuxxperts.com/enabling-core-dumps-in-embedded-systems/
  6. http://tieba.baidu.com/p/2365639005

2015年1月18日 星期日

[Embedded] Ubuntu的核心編譯

Below is the procedures to compile a linux kernel for ubuntu 

1.  get kernel source code 
$ sudo apt-get install linux-source
$ cp /usr/src/linux-source-3.13.0.tar.bz2 ~/ubuntu
$ cd ~/ubuntu
$ tar jxvf linux-source-3.13.0.tar.bz2

2. compile kernel
$ cd linux-source-3.13.0
$ make menuconfig
$ make

3. install new kernel
$ make modules_install
$ make install
$ update-initramfs -c -k

5. make sure kernel is build correctly
$ sudo ls /boot/*

6. check current kernel versuib
$ uname -r
// The original version is The new version is linux-source-3.13.0

7. After reboot
$ uname -r
// The new version is linux-source-3.13.0

2015年1月2日 星期五

用中文字找注音念法

小時候中文沒學好,常常看到某些複雜的字卻不會念,前陣子去吃了家火鍋,叫做溱洧陶養,看到店名,還跟老婆一起猜,到底是唸作溱(ㄓㄣ)洧(ㄨㄟˇ),還是唸作溱(ㄓㄣ)洧(一ㄡˇ)

為了要應付這種狀況,當下便想找個 app 幫忙查一下注音,可是沒想到 iOS 上面並沒有這種應用,我想可能是太簡單了,所以沒人想寫。所以只好自己來弄囉。以下針對這個 app 實作,作個記錄。

1. 輸入
預設的使用情境是看到某個字,卻不會念,因此想要查這個字的注音,所以提供使用者的輸入方式應該會有兩種,分別是
  • 透過手寫輸入法輸入,
  • 透過相機,拍下字,以此圖片當做輸入

2. 手寫輸入法輸入
以 iOS 而言,系統內本來便提供中文手寫輸入法,因此我們所需要的便是幫使用者把這個輸入法叫出來,讓使用者方便輸入。邏輯如下:
// 判斷 iPhone 上是否已經安裝中文手寫輸入法 
NSString *lang = [[UITextInputMode currentInputMode] primaryLanguage]; 
if ([lang isEqualToString:@"zh-Hant"]) { // 繁體中文輸入   // iPhone 上已安裝中文手寫輸入法   ;
}
else {
   // iPhone 上並無安裝中文手寫輸入法
   // 提醒使用者需安裝中文手寫輸入法才能使用,
   // 並且取消手寫輸入功能,只支援用圖片當成輸入來源。

   ;
}

3. 辨識圖片,找出中文字
圖片變成中文字的過程叫做OCR(Optical character recognition),此部份可以直接參考此Tesseract 的使用範例 
以下簡介此範例使用步驟,
1. Download and install
$ git clone https://github.com/pablosproject/iPhone-OCR-Tesseract-and-OpenCV.git
$ sudo gem install cocoapods
$ cd iPhone-OCR-Tesseract-and-OpenCV
$ pod setup
$ pod install 
2. setup
download Chinese (Traditional) language data for Tesseract 3.02 from https://code.google.com/p/tesseract-ocr/downloads/list
$ tar xvf tesseract-ocr-3.02.chi_tra.tar
$ cp tesseract-ocr/tessdata/* iPhone-OCR-Tesseract-and-OpenCV/infojobOCR/tessdata
$ open TestOCR.xcworkspace

4. 找注音
基本的想法很簡單,透過使用者的輸入,找到對應的中文字碼(BIG5 or UNICODE),到注音的字庫內找到對應的碼,在螢幕上顯示注音。 
iOS內的每個字元都是使用 UNICODE (UTF-16),中文碼的範圍介於4E00 ~ 9FFF之間(細節請參考全字庫),因此透過手寫輸入法所取得字,將其轉成 UTF-16 即可,查詢的方式可分為離線查詢,或線上查詢兩種

線上查詢 
可以直接登入此網頁,輸入對應的UNICODE即可,用法舉例如下:
 
若APP要支援此方法,便需要簡化操作與顯示頁面,當使用者輸入之後,使用CGI請此伺服器查詢資料,然後解析XML,直接取出第三頁內的部分資料提供使用者檢視,例如只取出發音子頁面。 
當然,如果要直接作個網頁介面連到此網站也是一種方式啦。 
離線查詢 
要用此方法,首先得需要有一個 unicode 與注音的對照表格,在iOS的注音輸入法內一定有個類似的表格,只是該如何取得對應資料。 
個人的想法是兩種方式都提供,預設使用離線查詢,若使用者想懂多一個對應的資訊,再幫打開全字庫的網頁。 

註:後來詢問老闆的結果是唸作(ㄓㄣ  ㄨㄟˇ ㄊㄠˊ 一ㄤˇ)

參考資料:
  1. 注音字母 與 Unicode 對照表
  2. U全字庫Unicode 字碼查詢
  3. 教育部終身教育司- 中文譯音轉換系統
  4. ios Managing the Keyboard

[Assembly] Relocation,以靜態聯結為範例

C code

/* a.c */
extern int shared;

int main()
{
    int a = 100;
    swap( &a, &shared );
}

/* b.c */
int shared = 1;

void swap( int* a, int* b )
{
    *a ^= *b ^= *a ^= *b;
}


Object file


$ gcc -c a.c b.c
$ ld a.o b.o -e main -o ab
$ objdump -h ab


$ objdump -t ab

Assembly code


 a.o 有兩個符號需要重新定位,shared 與 swap,其位置分別位於 0x15 與 0x21處。此處
  • R_386_32 表示 絕對定址修正(位址長度為 32bit,4 bytes)
  • R_386_PC32 表示 相對定址修正

    shared 與 swap 對應的程式碼對應如下
    • extern int shared;  --> line 11,暫時位址為 "0x00000000"
    • swap( &a, &shared ); --> line 20,暫時位址為 "0xFFFFFFFC"

    參考下述執行檔 ab,已經分別針對 shared 與 swap 重新定位
    • extern int shared; ,位址由 "0x00000000" 改為 "0x080490f8"
    • swap( &a, &shared ); ,位址由 "0xFFFFFFFC"  改為 "0x00000003",表示 swap函數的實際位址為  下個指令位址 + Offset = 0x080450b9 + 0x00000003 = 0x008480bc


    參考資料:
    1. 程式設計師的自我修養
    2. https://github.com/samuelololol/self-knowledgeable/tree/master/4