Powered by Drupal, an open source content management system

การประยุกต์ใช้งาน Embedded Linux Computer (ตอนที่ 13 - Cross Compile and Debugging)

Embedded Linux เป็นระบบที่มี Resources จำกัดโดยเฉพาะอย่างยิ่งหน่วยความจำ ดังนั้นการคอมไพล์โปรแกรมที่ใช้เนื้อที่ค่อนข้างเยอะจึงมักจะทำบนพีซีซึ่งมี Resources มากกว่า โดยคอมไพเลอร์ที่ใช้จะสร้างโคดหรือMachine Languageให้เหมาะสมกับการไปวิ่งบนซีพียูของ Embedded Linux อีกที โดยเราเรียกลักษณะนี้ว่า Cross Compile และตัว Compiler มักจะถูกเรียกว่า Cross Tool Chain
นอกจากการ Compile แล้ว สิ่งที่สำคัญไม่ยิ่งหย่อนไปกว่ากันคือการดีบัก ดังนั้นตอนนี้เราจะมาว่ากันด้วยเรื่องของการ Cross Compile และ Debugging กันครับ เพื่อปูทางสำหรับการ Compile โปรแกรมที่เราจะใช้งานสำหรับโปรเจ็คของเรา
 
CROSS COMPILE
 
ลองมาดูโคดง่ายๆและการคอมไพล์ปกติก่อนนะครับ
เริ่มต้นด้วยการสตาร์ท Ubuntu บน Virtualbox และสร้างไฟล์ชื่อ hello.c ภายใต้ directory test โดยมีข้อความดังนี้
#include <stdio.h>
 
int main(void)
{
 int i=0;
 for(i=0; i< 10;i++)
 {
  printf("Hello %d\n",i);
 }
  return 0;
}
 
ทำการ Compile ซอสโปรแกรม hello.c แล้ว ให้สร้าง output โปรแกรมชื่อ hellox86 ด้วยออฟชั่น -o ดังนี้
 
$ gcc hello.c -o hellox86
 
ใช้คำสั่ง file ตรวจสอบจะเห็นว่า hellox86 เป็น executable file ของ intel 80386
ซึ่งเราสามารถที่จะรันโปรแกรมบน PC ด้วยคำสั่ง
./hellox86
 
ในกรณีที่เราต้องการวิ่งโปรแกรมเดียวกันนี้บน ELC ของเราซึ่งมีซีพียูเป็น MIPS ก็ต้องทำการหา Cross Tool Chain มาคอมไพล์เสียก่อน สำหรับ Cross Tool Chain ไม่ต้องไปหาอื่นไกล เรามีอยู่แล้วซึ่งเป็นผลพวงจากการคอมไพล์ Kernel และสร้าง Image ไงครับโดย Cross Tool Chain จะอยู่ที่
~/openwrt/kamikaze/staging_dir/toolchain-mipsel_gcc-3.4.6_uClibc-0.9.30.1/usr/bin
 
 
วิธีการใช้ก็ทำดังนี้
1. เพิ่ม directory ที่มี cross tool chain เข้าไปใน PATH เสียก่อนด้วยคำสั่ง
 
export PATH=$PATH:/home/demo/openwrt/kamikaze/staging_dir/toolchain-mipsel_gcc-3.4.6_uClibc-0.9.30.1/usr/bin
 
2. หลังจากมี PATH แล้วเราก็สามารถเรียกใช้โปรแกรม Cross Compiler สำหรับ MIPS ดังนี้
mipsel-openwrt-linux-gcc hello.c -o hellomips
 
3. เมื่อตรวจสอบชนิดของไฟล์ จะเห็นว่า hellomips จะเป็น executable file ของ MIPS
 
ซึ่งแน่นอนครับเราคงไม่สามารถที่จะวิ่ง MIPS บน 80x86 ได้แน่นอน ดังนั้นต้องทำการถ่ายโอนไปวิ่งบน  ELC ของเราก่อนครับ
 
 
คราวนี้ผมใช้คำสั่ง scp (secure copy) ในการ copy file hellomips จากเครื่องที่วิ่ง ubuntu (ip address = 192.168.1.114) มายัง directory /root ของ ELC แล้วทำการรันโปรแกรมครับ (demo หน้า @ คือ username ของผมครับ ยังจำกันได้ไม๊เอ่ย)
จะเห็นว่าโปรแกรมสามารถวิ่งบน ELC เหมือนบนพีซีทุกประการ
 
DEBUGGING
 
การคอมไพล์ก็ย่อมต้องคู่กับการดีบัก ในระบบลินุกซ์โปรแกรมที่ใช้ในการดีบักคือ gdb ซึ่ง gdb ที่มากับ ubuntu จะเป็นตัวที่ใช้สำหรับดีบักโคดของ 80x86 เท่านั้น ไม่สามารถใช้ดีบักโดคของ MIPS ได้
งั้นเราก็ทำการติดตั้ง gdb ที่คอมไพล์สำหรับ MIPS บน ELC แล้วดีบักบนตัว ELC เองเลยสิ ช้าก่อน!! ถึงแม้จะมี gdb ที่วิ่งบน WRT54GLได้ (ลองค้นดูได้ด้วยคำสั่ง opkg list| grep gdb และติดตั้งได้คำสั่ง opkg install gdb) แต่เนื่องจาก memory ของ WRT54GL มีน้อยมาก อย่าว่าแต่รันเลย ติดตั้งยังมีที่ไม่พอเลย
อ้าว!!! แล้วจะทำยังไงดีล่ะทีนี้
ยังครับ ยังไม่หมดหนทาง เรายังมีอีกทางนึงที่เรียกว่า Remote Debugging ครับ ลองมาดูกันสักนิดครับว่า Remote Debugging เป็นยังไง
 
 
Remote debugging จะประกอบด้วยโปรแกรมหลักสองตัว
1. gdbserver จะเป็นโปรแกรมเสริมที่จะทำให้เราสามารถใช้ gdbจากเครื่องที่มีประสิทธิภาพสูงกว่าไปทำการดีบักโปรแกรมที่วิ่งอยู่บนELC โดยตัวgdbserverจะมีขนาดเล็กและติดตั้งอยู่บนELCทำหน้าที่เป็นserverคอยรับคำสั่งจากgdb การติดตั้งทำได้ง่ายเพียงใช้คำสั่ง
 
$ opkg update
$ opkg install gdbserver
 
2. gdb สำหรับ gdb ที่เราจะใช้ดีบักtargetของเราซี่งเป็นซีพียูตระกูลMIPS เราจำเป็นต้องใช้ gdb ที่ทำการคอมไพล์เป็นพิเศษเพื่อการนี้โดยเฉพาะ โดยตัวนี้เรายืมมาจากอีกโปรเจ็คนึงซึ่งเป็นต้นตระกูลของOpenWrtอีกทีก็คือโครงการ buildroot.org
สำหรับ buildroot.org เป็นโครงการที่ใช้สร้าง Embedded Linux ทั้งระบบ (bootloader, kernel, filesystem) โดยเชี่ยวชาญการสร้าง linux uClibc ซึ่งเป็น linux สำหรับซีพียูที่ไม่มี mmu (memory management unit) แต่เราจะยืมมาบางส่วนเท่านั้นที่เกี่ยวกับ gdb
 
สร้าง gdb สำหรับ debug MIPS
 
1. เข้า VirtualBox/Ubuntu เปิด console และพิมพ์ข้อความดังนี้
$ mkdir buildroot  สร้าง directory buildroot
$ cd buildroot
$ wget http://www.buildroot.org/downloads/buildroot-2009.08.tar.gz   ดึงซอสไฟล์
$ tar xvzf buildroot-2009.08.tar.gz  แตกซอสไฟล์
 
2. ซอสไฟล์จะถูกแตกอยู่ภายใต้ directory buildroot-2009.08
เข้าไปใน buildroot-2009.08 แล้ว make menuconfig
3. เลือก Target Architecture เป็น mipsel
เลือก Target Architecture Variant เป็น mips32 แล้วไปยังตัวเลือก Toolchain
 
 
4.เลือก Build gdb for the host แล้วexit ออกจาก make menuconfig โดยเลือก save configuration
 
5. ก่อนทำการ make เราจำเป็นต้องติดตั้งโปรแกรมเพิ่มอีกสองตัวดังนี้
$ sudo apt-get install bison
$ sudo apt-get install gettext
$ make
 
6. เมื่อจบการ make เราจะได้โปรแกรม mips-linux-uclibc-gdb สำหรับการดีบัก MIPS ภายใต้ directory ~/buildroot/buildroot-2009.08/build_mips/staging_dir/usr/bin
 
 
มาถึงจุดนี้ เราก็มีโปรแกรมที่จำเป็นสำหรับการทำ Remote Debugging พร้อมแล้วงั้นมาลองดูกันเลยครับ
 
ปฎิบัติการณ์ Remote Debugging
 
1. คอมไพล์โปรแกรมใหม่เพื่อให้เหมาะสำหรับการใช้ gdb ดังนี้
$ mipsel-openwrt-linux-gcc hello.c -Wall -ggdb -o hellomips
โดยเพิ่ม Option อีกสองตัวคือ -Wall และ -ggdb
-ggdb สำหรับ Produce debugging information for use by GDB (http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Debugging-Options.html#Debugging-Options)
 
2. ตรงหน้าจอของ ELC ให้ดึงไฟล์ hellomips ที่คอมไพล์ใหม่เรียบร้อยแล้วไปยัง ELC ด้วยคำสั่ง scp แล้วรันโปรแกรม gdbserver ดังนี้
gdbserver จะเปิดโปรแกรม hellomips แล้วรอรับคำสั่งจาก gdb ที่จะติดต่อเข้ามายัง port หมายเลข 1234
 
3. คราวนี้ย้ายมายังจอของ Host PC ของเราแล้วทำดังนี้
3.1 เรียกใช้ mipsel_linux_ublibc-gdb แล้วเปิดโปรแกรม hellomips 
~/buildroot/buildroot-2009.08/build_mipsel/staging_dir/usr/bin/mipsel-linux-uclibc-gdb hellomips
 
3.2 โปรดสังเกตุว่า gdb ของเราจะเป็นตัวพิเศษที่คอมไพล์เพื่อรันบนHost=i386 และดีบัก Target=mipsel
 
3.3 เนื่องจากโปรแกรมที่ถูกดีบักจะวิ่งโดยมีlibraryประกอบ ซึ่ง lib ที่ใช้ในกรณีนี้เป็นของ mips ดังนั้นเราจึงต้องแจ้งให้ gdb รู้ด้วยว่าจะไปโหลด lib เพื่อทำการดีบักได้จากที่ไหน ไฟล์ที่อยู่บนHostภายใต้  /home/demo/openwrt/kamikaze/staging_dir/target-mipsel_uClibc-0.9.30.1/root-brcm-2.4/lib/ ก็คือไฟล์เดียวกันกับที่อยู่ใน  /usr/lib ของ Target เรานั่นเอง ดังนั้นบอก gdb ด้วยคำสั่ง
 
set solib-search-path /home/demo/openwrt/kamikaze/staging_dir/target-mipsel_uClibc-0.9.30.1/root-brcm-2.4/lib/
 
3.4 ทำการเชื่อมต่อกับ gdbserver ของเราด้วยคำสั่ง target remote 192.168.1.111:1234
 
4. มาลองใช้ gdb กันดูสักหน่อยนะครับ
พิมพ์ list เพื่อแสดงซอสโคด
พิมพ์ break 8 เพื่อให้หยุดตรงบรรทัดที่ 8 ซึ่งเป็น printf
พิมพ์ cont เพื่อทำการวิ่งโปรแกรมจนไปถึง break point
พิมพ์ cont หนที่สอง โปรแกรมจะทำการพิมพ์ printf , วนกลับไปเพิ่มค่า i แล้ววนกลับมาหยุดตรงบรรทัดที่ 8 โปรดสังเกตุหน้าจอ telnet ของ ELC จะมีการพิมพ์เกิดขึ้น
พิมพ์ cont หนที่สาม โปรแกรมจะทำเช่นเดิม และกลับมาหยุดตรงบรรทัดที่แปด
 
5. พิมพ์ print i เพื่อลองดูค่า i และออกจากโปรแกรมโดยพิมพ์ q
 
ไม่ยากใช่ไม๊ครับสำหรับการRemote Debugging เครื่อง ELC ของเรา
แถมท้าย
บางคนอาจจะนึกทำไมไม่มีโปรแกรมกราฟฟิคช่วยดีบักบนลินุกซ์หรือไง มีครับ ลองมาดูนี่เลยครับ
1. ติดตั้งโปรแกรม ddd (data display debugger) บน Host PC
$ sudo apt-get install ddd
 
2. Start gdbserver บน ELC
# gdbserver localhost:1234 hellomips
 
3. เริ่มโปรแกรม ddd ด้วยคำสั่ง
$ ddd --debugger ~/buildroot/buildroot-2009.08/build_mipsel/staging_dir/usr/bin/mipsel-linux-uclibc-gdb hellomips
หมายเหตุ
เนื่องจาก ddd ใช้ได้กับ debugger หลายตัวดังนั้น ออฟชั่น --debugger ใช้สำหรับบอก ddd ว่าจะใช้ debugger ตัวใด ในกรณีนี้เราใช้ตัว mipsel-linux-uclibc-gdb ของเรา
 
จะเห็นว่า ddd จะทำการแสดงซอสโปรแกรมเราโดยอัตโนมัติ
4. กำหนด library และ เชื่อมต่อกับ gdbserver ด้วยคำสั่งปกติของ gdb ในช่องด้านล่าง
set solib-search-path /home/demo/openwrt/kamikaze/staging_dir/target-mipsel_uClibc-0.9.30.1/root-brcm-2.4/lib/
target remote 192.168.1.111:1234
 
 
5. คลิ๊กตรงหน้าบรรทัด printf แล้วคลิ๊กปุ่ม break เพื่อกำหนด break point
 
6. คลิ๊กปุ่ม cont เพื่อวิ่งจนไปถึง break point จะเห็นสัญลักษณ์ลูกศรสีเขียวหน้าสัญลักษณ์ stop จากนั้นให้ลองคลิ๊กเมนู Data แล้วเลือก Display Local Variables จะเห็นว่า หน้าต่างด้านบนจะแสดงค่าของ i ให้เราเห็น
 
7. ลองกดปุ่ม step ที่อยู่ทางขวาดูหลายๆหน จะสังเกตุเห็นการเคลื่อนไหวของโปรแกรมขณะวิ่งไปยัง step ต่างๆ พร้อมกับค่า i จะ update ไปด้วย
 
โดยหน้าต่าง telnet ของ ELC ก็จะแสดงการทำงานจริงไปพร้อมๆกัน
 
 
จบตอนครับ ยาวไปสักนิดนะครับสำหรับตอนนี้ ตอนต่อไปจะมาว่าด้วยเรื่องการเชื่อมต่อโปรแกรมอ่าน input จาก i2c เข้ากับระบบเวบเพจเพื่อที่เราสามารถที่จะตรวจสอบสภาวะของประตูในโรงจอดรถได้จากทุกที่ในโลกที่อินเตอร์เน็ทเข้าถึงครับ