2007年12月30日 星期日

新年快樂

2007 年再 26.5 小時後就結束了…
發生了好多事。

希望 2008 年是會大好年。

2007年11月3日 星期六

Quilt - Patches 整合 Script

在社群中開發程式往往是用 patch 來做來開發工具。
Developer 會在 mail list 上發 patch 出來,而 Maintainer 會把這些 patches 整合起
個,做好 review 再一個一個 commit 上 mainstream 之中。而當 Patch 的量很大,而又>有相依性之時…
一個 Open Source Project 的 Maintainer 要如何管理這些 Patch 呢?

[Quilt]就是這樣的一個好用的工具。

假設今天你在 maintain 一個案子,叫 ”mypro“ 放在 /work/mypro 底下而你拿到了 5 個
patches
001_ooxx.patch
002_lalal.patch
003_lele.patch
004_bad.patch
005_conflict.patch

你可以在 /work/mypro/ 下建立一個 patches 的目錄 (如果想自已指定請 export QUILT_PATCHES="....")
把 patches 放在 /work/mypro/patches 之中
再建一個檔案 /work/mypro/patches/series 把這五個patches 依序寫入 series 中,一行一個 patch, 如果有base 目錄不同的問題 (quilt default 是打 patch -p1) 可在後面加上 -p.
假設 003_lele.patch 這個 patch 是在 /work/mypro 下用 svn diff > 003_lele.patch 做出來的, 那在 series 之中就要寫成:
003_lele.patch -p0

所以 series 就會變成
---------------------
001_ooxx.patch
002_lalal.patch
003_lele.patch -p0
004_bad.patch
005_conflict.patch
---------------------

如此設好之後,就可以用 "quilt push" 打 patch ,用 "quilt pop " 退回上層…
如果要一次打完所有 patch 可以用 quilt push -a 一次打完…想退回 code base 時,就用 quilt pop -a 一路退到底。

可以用 quilt top 看你上一個打的 patch 是那個 patch ,用 quilt next 看下一個是那個 patch
如果發現 patch 有些地方需要修改,可以用quilt edit <檔案> 做修改…修改好了之後,可以用 quilt refresh 把修改寫入 "上一個打的 patch" ,也就是 quilt top 看得到的那個。

如果要寫新的 patch 可以用 quilt new ,加上 quilt edit <要修改的檔名>,做完後用 quilt refresh 把 diff 寫入 patch。

因為你打了多個 patch 之後 svn diff 就會混合了多個 patch ,如果只想看上個打的 patch 的影響可用 quilt diff 來看。

一般來說,如果你要手動修改你的 series 檔。可先 quilt pop -a 退回 code base 再做修改…如手動 mark 掉一些patch 或加上註解,註解是由 '#' 做為開頭。

如果code base 改變了…可 quilt pop -a 退回開頭,再 svn update (cvs ),再把一些已被 commit 的 patch remove 掉(這個要檢查一下,一般來說有 commit 都會說明 commit 了那些 patch ),再一個一個 push 回來

而如果你想 commit code 時,也可一面 push 一面 commit 。等 commit 完了,再把 series 裏已 push 且 commit 的 patch mark 掉,然後直接砍掉 /work/mypro/.pc 這個目錄…這是 quilt 管理 diff 的目錄…如此就可以直接可 upstream 同步。 (如果你是 maintainer )

當你要 release patch 到 mail list 前,可以把你的 code base 的版號(最好是 HEAD),和你之前相依的 patch (如果有的話),一起 release 出來。如果 release 的 patch 多於兩個。最好也把 series release 出來。

--
Reference:
How To Survive With Many Patches or Introduction to Quilt

2007年10月28日 星期日

十年

人總是在失去後才覺得珍貴。

這幾天正好是我們認識十週年,雖然分手好一段時間了,而我們又各自有了新的戀情。
聽到這首歌,份外有感覺。

對不起,我們錯過了…


十年 - 陳奕迅 曲︰陳小霞 詞︰林夕 編︰陳輝陽
如果那兩個字沒有顫抖
我不會發現我難受
怎麼說出口 也不過是分手
如果對於明天沒有要求
牽牽手就像旅遊 成千上萬個門口
總有一個人要先走

懷抱既然不能逗留 何不在離開的時候
一邊享受 一邊淚流

十年之前 我不認識你
你不屬於我 我們還是一樣
陪在一個陌生人左右
走過漸漸熟悉的街頭

十年之後 我們是朋友
還可以問候 只是那種溫柔
再也找不到擁抱的理由
情人最後難免淪為朋友

直到和你做了多年朋友
才明白我的眼淚 不是為你而流
也為別人而流

2007年10月22日 星期一

Stack Dump Debug Tip

In developing embedded system, developer may encounter an ambiguous condition that the system so limited that cannot run gdb, and the network is also too unstable to run gdb-server. And the rootfs is too small that core dump is not available. In such miserable condition there is still a powerful debug skill: stack dump.

Before using this skill, we have to know how a program runs. The stack's bottom is at higher address in memory, and it growth toward lower address.


And program accesses memory from low to high. That is we can use printf("%x %x"); to print out the data in stack.

Another important tip is CFLAGS += -finstrument-functions. This flag make us can insert code when entering and exiting a function. This way, we can construct our own stack dump without the help of gdb. If you turn the flag -finstrument-functions on, you should implements the following two functions:
void __cyg_profile_func_enter(void *func,void *caller) __attribute__((__no_instrument_function__));
void __cyg_profile_func_exit(void *func,void *caller) __attribute__((__no_instrument_function__));

These functions are designed for profiling and analysing code performance and coverage. In this case use use it to create a function stack.

We can use signal() to set the signal handler to dump the stack when a signal received.

Here are the demo codes:

----------------------------------------------------------------
### File: Makefile
CFLAGS=-finstrument-functions -g2
CC=gcc

all:
gcc $(CFLAGS) -o stackdemo stackdemo.c stack_util.c
----------------------------------------------------------------
/** @file stack_util.h
* @auther Tick
* @License GPL
*/


#ifndef __TICK_DEMO_STACK___
#define __TICK_DEMO_STACK___

void setSignalHandler();
void SignalHandler(int) __attribute__((__no_instrument_function__));
void DumpStack(int sig) __attribute__((__no_instrument_function__));
void __cyg_profile_func_enter(void *func,void *caller) __attribute__((__no_instrument_function__));
void __cyg_profile_func_exit(void *func,void *caller) __attribute__((__no_instrument_function__));

#endif
----------------------------------------------------------------
/** @file stack_util.c
* @auther Tick
* @License GPL
*/


#include "stack_util.h"

#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>


#define _STACK_BUFFER_SIZE 4096
void *__stack_buffer_[_STACK_BUFFER_SIZE];
int __stack_pid_buffer[_STACK_BUFFER_SIZE];
int __stack_buffer_index__private__ =0;
volatile int __stack_spin_lock__=0;
inline void dumpstack() {
int i,max=__stack_buffer_index__private__;
printf("Stack Trace:\n");
for (i=0;i<__stack_buffer_index__private__;i++) {
printf("[%3d] pid:[%3d] 0x%08x\n",i,__stack_pid_buffer[i],__stack_buffer_[i]);
}
}

void setSignalHandler() {
int ans;
struct sigaction act,oldact;
act.sa_handler=DumpStack;
act.sa_flags= SA_ONESHOT | SA_NOMASK;
//act.sa_flags= SA_RESETHAND;
ans=sigaction(SIGUSR1,&act,&oldact);
if (ans) {
printf("Set SIGUSR1 Failed!!!!!\n");
printf ("ErrorNumber: %d\n",errno);
}else {
printf("Set SIGUSR1 OK!!!!!\n");
}

signal(SIGHUP,SignalHandler);
signal(SIGINT,SignalHandler);
signal(SIGQUIT,SignalHandler);
signal(SIGILL,SignalHandler);
signal(SIGKILL,SignalHandler);
signal(SIGSEGV,SignalHandler);
signal(SIGTERM,SignalHandler);
signal(SIGPWR,SignalHandler);
}

void DumpStack(int sig) {
struct sigaction act,oldact;
act.sa_handler=DumpStack;
act.sa_flags= SA_ONESHOT | SA_NOMASK;
sigaction(SIGUSR1,&act,&oldact);

printf("Stack:\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n");

printf ("Signal Type: %d\n",sig);
printf ("ErrorNumber: %d\n",errno);
printf ("PID: %d\n",getpid());
dumpstack();
}

void SignalHandler(int sig) {
if (sig==SIGTERM || sig==SIGKILL) {

//close device here
}
if (sig==SIGTERM) {
printf ("Signal Type: %d\n",sig);
printf ("PID: %d goes die\n",getpid());
fflush(stdout);
fflush(stderr);
sleep(1);
exit(0);
}

printf("Stack:\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n");

printf ("Signal Type: %d\n",sig);
printf ("ErrorNumber: %d\n",errno);
printf ("PID: %d\n",getpid());
printf ("\n");
dumpstack();
fflush(stdout);
fflush(stderr);
if (sig==SIGSEGV || sig==SIGILL) {
//exit(EXIT_FAILURE);
// If you want to kill whole tick when page fault happens
// please USE "exit(EXIT_FAILURE);"
_exit(129);
}
}


void __cyg_profile_func_enter(void *func,void *caller) {
while (__stack_spin_lock__) ;
__stack_spin_lock__=1;
if (__stack_buffer_index__private__ < _STACK_BUFFER_SIZE) {
__stack_buffer_[__stack_buffer_index__private__]=func;
__stack_pid_buffer[__stack_buffer_index__private__]=getpid();
__stack_buffer_index__private__++;
}
__stack_spin_lock__=0;
}
void __cyg_profile_func_exit(void *func,void *caller) {
while (__stack_spin_lock__) ;
__stack_spin_lock__=1;
int i,pid=getpid();
if (__stack_buffer_index__private__ > 0) {
for (i=__stack_buffer_index__private__-1;i >0;i--) {
if (__stack_pid_buffer[i]==pid) {
break;
}
}
for (;i<__stack_buffer_index__private__-1;i++) {
__stack_buffer_[i]=__stack_buffer_[i+1];
__stack_pid_buffer[i]=__stack_pid_buffer[i+1];
}
__stack_buffer_index__private__--;
}
__stack_spin_lock__=0;
}
----------------------------------------------------------------
/**
* @file stackdemo.c
* @author Tick
* @license GPL
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include "stack_util.h"

struct LALA {
int data;
int lala;
};

void run_me_will_crash_null_point () {
struct LALA *lala=NULL;
lala->lala++;
}

void run_me_will_crash_divid_zero() {
int a=1;
int b= 200/ --a;
}

void run_me_will_crash_buffer_overflow() {
char buf[4];
char *src;
src =(char *) malloc (64);
memset(src,'A',64);
memcpy(buf,src,64);
}


void prompt() {
printf("What way do you want to die?\n");
printf("1. segment fault\n");
printf("2. divid zero\n");
printf("3. buffer overflow\n");
printf("> ");
}

void do_die () {
char buf[128];
while(1) {
prompt();
fgets(buf,sizeof(buf),stdin);
if (isdigit(buf[0])) {
switch (buf[0]) {
case '1':
run_me_will_crash_null_point();
break;
case '2':
run_me_will_crash_divid_zero();
break;
case '3':
run_me_will_crash_buffer_overflow();
break;
default:
continue;
}
}
}
}

void showmaps() {
char buf[128];
sprintf(buf,"cat /proc/%d/maps",getpid());
system(buf);
}

void function_D() {do_die();}
void function_C() {function_D();}
void function_B() {function_C();}
void function_A() {function_B();}
int main (void) {
setSignalHandler();
showmaps();
function_A();
}
----------------------------------------------------------------


The following is the execution result:

----------------------------------------------------------------

tick@tock:~/work/demo>./stackdemo
Set SIGUSR1 OK!!!!!
08048000-0804a000 r-xp 00000000 08:03 127325 /home/tick/work/demo/stackdemo
0804a000-0804b000 rw-p 00001000 08:03 127325 /home/tick/work/demo/stackdemo
0804b000-08053000 rw-p 0804b000 00:00 0 [heap]
b7dc7000-b7dc8000 rw-p b7dc7000 00:00 0
b7dc8000-b7f0c000 r-xp 00000000 08:03 121895 /lib/tls/i686/cmov/libc-2.6.1.so
b7f0c000-b7f0d000 r--p 00143000 08:03 121895 /lib/tls/i686/cmov/libc-2.6.1.so
b7f0d000-b7f0f000 rw-p 00144000 08:03 121895 /lib/tls/i686/cmov/libc-2.6.1.so
b7f0f000-b7f12000 rw-p b7f0f000 00:00 0
b7f25000-b7f28000 rw-p b7f25000 00:00 0
b7f28000-b7f42000 r-xp 00000000 08:03 121912 /lib/ld-2.6.1.so
b7f42000-b7f44000 rw-p 00019000 08:03 121912 /lib/ld-2.6.1.so
bfc0f000-bfc24000 rw-p bfc0f000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
What way do you want to die?
1. segment fault
2. divid zero
3. buffer overflow
> 1
Stack:
0x00000001 0xbfc22948 0xffffe420 0x0000000b 0x00000033 0xc02f0000 0x0000007b 0x0000007b
0x00000000 0xb7f42ce0 0xbfc22948 0xbfc22920 0xb7f0dff4 0x00000000 0xb7f0dff4 0x00000000
0x0000000e 0x00000004 0x08048837 0x00000073 0x00210286 0xbfc22920 0x0000007b 0x00000000
0x00000000 0x00000004 0xb7f38068 0x00000011 0x00000008 0xb7f42ff4 0xb7f28468 0xb7f28000
0xbfc226e8 0xbfc22704 0x00000000 0xbfc22800 0xbfc226dc 0xbfc22768 0xb7df2b5a 0xbfc22818
0xbfc226e8 0x00000080 0x00000000 0x00000000 0xb6d55b68 0x00000000 0x00000000 0x00000000
0x00000000 0xb7f27db4 0xb7f303e2 0xb7f12000 0x00013425 0xb7f42ff4 0xbfc22aa4 0xb7f2b22b
0xb7f432a0 0xb7f43820 0x00000000 0x00000000 0x00000000 0x00000000 0xbfc2286c 0x00000000
0xbfc227d4 0xb7df2b13 0xbfc227e0 0xb7f0ef64 0x00000080 0x08048ec0 0x10000000 0xb7f27b38
0x00000004 0x080484f4 0x0d696910 0xb7f27b38 0xbfc2279c 0xb7f30c0b 0xb7dd9df6 0x080484ea
0xb7f43941 0x080484ea 0x0d696913 0xb7f27b48 0xbfc227bc 0xb7f30c0b 0xb7dd9e74 0x080484e0
0xb7f43941 0xb7f43934 0xb7dd0dac 0xbfc2000d 0xb7f35c99 0x080483e8 0xb7f43940 0xb7f42ff4
0xbfc22800 0xb7f27b0c 0xbfc22834 0xb7f30fc0 0xb7e2e0d4 0xb7e983b8 0xb7f0e440 0xb7f0dff4
0xb7f3efbc 0xbfc22800 0xbfc228e4 0x22494966 0x00000003 0xb7dcbc4c 0xb7dcada0 0xffffffff
0x22494966 0x0000000b 0xbfc22828 0x00000000 0x00000000 0x00000001 0x00000516 0xb7f27b48
0xb7f27858 0x08048467 0xb7dd485c 0x08048308 0x00000001 0xb7f42ff4 0xb7f43820 0xbfc228d8
0xbfc228f4 0xb7f31166 0x08048308 0xbfc228d8 0xb7f437c4 0x00000001 0xb7f27b48 0x00000001
0x00000000 0x00000001 0xffffffff 0xbfc22884 0xb7e2c179 0xb7f0e4e0 0xb7f25000 0x00000002
0xbfc228a4 0xbfc228e4 0xbfc22920 0xb7f43668 0x08048467 0x22494966 0x00000000 0x00000000
0x00000400 0xb7f0dff4 0xb7f0e440 0x00000000 0xbfc228b4 0xb7e2d50b 0xb7f0e440 0xb7f0e440
0xbfc228cc 0xb7e2e8d4 0xb7f0e440 0xb7e2b86f 0xb7f0dff4 0xb7f24001 0x00000001 0xb7e2206d
0xbfc22975 0xb7dd0dac 0xb7f27858 0x00000001 0xffffffff 0xb7f42ff4 0x08048308 0xb7f43668
0xbfc22930 0xb7f34e73 0xb7f43820 0xb7f27b48 0x00000001 0x00000001 0x00000000 0x0077b858
0x80cd0000 0xbfc22948 0x0804882d 0x08048814 0x08048ac2 0xb7f42ce0 0x00000000 0xbfc229f8
0xb7f3a660 0xb7f0f0c4 0xbfc22974 0xb7dec4d0 0x00000000 0xbfc229f8 0x08048ac2 0xbfc22974
0x00000080 0xb7f0e440 0xb7f27858 0x00000000 0x00000031 0xb7f42ff4 0x08048298 0xb7f43668
0xbf000a31 0xb7f34e73 0xb7f43820 0xb7f27b38 0x00000001 0x00000001 0x00000000 0x0804847c
0x00000006 0x00000000 0x0804acc4 0xb7dd106c 0xb7dff940 0xbfc229b4 0x08049039 0xbfc22a78
0x0000188d 0x00000000 0xb7f0dff4 0x00000001 0x0000188c 0xbfc22a78 0x08048b3f 0x08048ad8
0x08048c4c 0x0000188c 0x0d696910 0x00000000 0x080f0d30 0x08048e34 0x08048ff7 0xbfc22a98
0xff0a0000 0xbfc22a18 0x08048b70 0x08048b52 0x08048ba3 0xb7f42ff4 0x08048ff7 0xb7f43668
0xb7f0dff4 0xbfc22a38 0x08048ba3 0x08048b85 0x08048bd6 0x00000001 0x08048ff7 0x0804843b
0xb7f0dff4 0xbfc22a58 0x08048bd6 0x08048bb8 0x08048c09 0xb7f42ce0 0x08048ff7 0xbfc22a78
0xb7f0dff4 0xbfc22a78 0x08048c09 0x08048beb 0x08048c51 0xb7e5bc08 0xc0000000 0xb7ed2939
0xff0a0000 0xbfc22a98 0x08048c51 0x08048c1e 0xb7dde050 0xbfc22aa8 0x080490f9 0xb7f35800
0xbfc22ab0 0xbfc22b08 0xb7dde050 0xb7f42ce0 0x080490e0 0xbfc22b08 0xb7dde050 0x00000001
0xbfc22b34 0xbfc22b3c 0xb7f43820 0x00000000 0x00000001 0x00000001 0x00000000 0xb7f0dff4
0xb7f42ce0 0x00000000 0xbfc22b08 0x90556081 0xafc02a91 0x00000000 0x00000000 0x00000000
0xb7f3a660 0xb7dddf7d 0xb7f42ff4 0x00000001 0x08048790 0x00000000 0x080487b1 0x08048c1e
0x00000001 0xbfc22b34 0x080490e0 0x080490d0 0xb7f35800 0xbfc22b2c 0xb7f3fead 0x00000001
0xbfc23864 0x00000000 0xbfc23870 0xbfc23883 0xbfc238ba 0xbfc238ca 0xbfc238de 0xbfc238e9
0xbfc23938 0xbfc23953 0xbfc2398c 0xbfc2399e 0xbfc239a8 0xbfc23c23 0xbfc23c59 0xbfc23c89
Signal Type: 11
ErrorNumber: 22
PID: 6284

Stack Trace:
[ 0] pid:[6284] 0x08048c1e
[ 1] pid:[6284] 0x08048beb
[ 2] pid:[6284] 0x08048bb8
[ 3] pid:[6284] 0x08048b85
[ 4] pid:[6284] 0x08048b52
[ 5] pid:[6284] 0x08048a1e
[ 6] pid:[6284] 0x08048814
[ 7] pid:[6284] 0x08048c70

----------------------------------------------------------------
You can use "objdump -S -x stackdemo | less" to find out the address's corresponding function.

. If the function crashed in library, you can using the address - the address of library (shown in /proc/xxx/maps) and find out the offset. This offset is the crash point in library. (using objdump)

2007年9月23日 星期日

簡易版 Minicom

昨天坐車下南部,在車上心血來潮想在 NEO1973上玩Minicom 結果發現手上沒有 minicom的 package。人在車上又沒有網路…想玩東西又沒得玩…就自已寫嘍…
然後就在車上開始 coding ...
發現還蠻有趣的,大概到台中的時候完成,之後就在車上一直玩…
玩到 Notebook 沒電 @_@ 4 cell 的電池果然是不夠力啊

執行檔是 tickminicom
使用方法是 ./tickminicom [device] [speed]
default 的 device 是 /dev/ttySAC0 ,speed 是 115200
跳脫字元是 '%'

因為是自已寫的,所以可以很直接的測試幾個想知道的性質…

Filename: Makefile




CC=arm-angstrom-linux-gnueabi-gcc
all:
$(CC) -o tickminicom tick_minicom.c util.c
gcc -o tickminicom_x86 tick_minicom.c util.c



Filename: debug.h




#ifndef __MPENV_DEBUG_H__
#define __MPENV_DEBUG_H__

#include <assert.h>

#define CONFIG_DEBUG

#ifdef CONFIG_DEBUG
#include <stdio.h>
#define debug(f, a...) \
do{ \
printf ("DEBUG: (%s, %d): %s: ",__FILE__, __LINE__, __FUNCTION__); \
printf (f, ## a); \
} while (0)
#else
#define debug(f, a...)
#endif

#define error(f, a...) \
do{ \
printf ("ERROR: (%s, %d): %s: ",__FILE__, __LINE__, __FUNCTION__); \
printf (f, ## a); \
} while (0)


#endif




Filename: util.h




#ifndef __TICK_MINICOM_UTIL_H__
#define __TICK_MINICOM_UTIL_H__

#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

/// Be aware 'x' cannot be a expression or this function cause unpredicable result.
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

struct bdrt {
int bps;
u_int32_t b;
};

static struct bdrt bdrts[] = {
{ 0, B0 },
{ 9600, B9600 },
{ 19200, B19200 },
{ 38400, B38400 },
{ 57600, B57600 },
{ 115200, B115200 },
{ 230400, B230400 },
{ 460800, B460800 },
{ 921600, B921600 },
};

int getche(int fd);

int open_device(char *device,int speed);

int set_baud(int fd,int rate);

#endif




Filename: util.c




#include "util.h"
#include "debug.h"
#include <string.h>

int getche (int fd) {
int i;
char ch;
struct termios old, new;
tcgetattr (fd, &old);
memcpy (&new,&old, sizeof (struct termios));
new.c_lflag = ~(ICANON | ECHO);
tcsetattr (fd, TCSANOW,&new);
i = read (fd,&ch, 1);
tcsetattr (fd, TCSANOW, &old);
if (i == 1) {
return ch;
}
else {
debug("fd %d ERROR\n",fd);
return -1;
}
}

int set_baud(int fd,int rate) {
int i,rt;
u_int32_t bd = 0;
struct termios ti;
for (i = 0; i < ARRAY_SIZE(bdrts); i++) {
if (bdrts[i].bps == rate) {
bd = bdrts[i].b;
break;
}
}
if (bd==0) {
error("Cannot set Baud Rate!!\n");
return -1;
}
rt = tcgetattr(fd, &ti);
if (rt<0) {
error ("Cannot get attr i=%d\n",rt);
return rt;
}
rt = cfsetispeed(&ti, B0);
if (rt<0) {
error("Cannot set input baud to B0!!\n");
return rt;
}
debug("Open uart with speed %d\n",bdrts[i].bps);
rt = cfsetospeed(&ti, bd);
if (rt < 0) {
error("Cannot set baud rate %d\n",bdrts[i].bps);
return rt;
}
ti.c_cflag |= CRTSCTS; // hardware control
return tcsetattr(fd, 0, &ti);
}

/**
* Open Uart for testing
* return value is the fd
*/

int open_device (char *device,int speed) {
int fd;
if (device==NULL) {
error("device is invalid (NULL pointer)\n");
return -1;
}
debug("Try to open device %s!\n",device);
fd = open(device,O_RDWR);
if (fd < 0) {
error("cannot open uart %s, fd is %d\n",device,fd);
error("%s\n",strerror(errno));
return -1;
}
if (set_baud(fd,speed) < 0) {
error("Set Baud rate failed!!\n");
return -1;
}
return fd;
}




Filename: tick_minicom.c




/**
* @file tick_minicom.c
* @brief a tiny uart client
* @license GPL (General Public License)
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "debug.h"
#include "util.h"

#define DEFAULT_UART "/dev/ttySAC0"
#define DEFAULT_BAUD 115200

static int keep_run=1;



/// Set '%' as the escape code
void input_command(int input,int output) {
int i;
char buf[1];
while(keep_run) {
i=getche(input);
if (i< 0) {
debug("file closed!!\n");
keep_run=0;
break;
}
if (i=='%') {
debug("User entered the escape code.\n");
debug("Exiting program!\n");
keep_run=0;
break;
}
buf[0]=i;
write(output,buf,1);
}
}

void read_from_uart(int input,int output) {
int i;
char buf[1];
while (keep_run) {
i=getche(input);
buf[0]=i;
i=write(output,buf,1);
}
}

int main (int args,char **argv) {
int uart;
int pid;
char buf[128];
if (args==1) {
uart=open_device(DEFAULT_UART,DEFAULT_BAUD);
} else if (args==2) {
uart=open_device(argv[1],DEFAULT_BAUD);
} else {
uart=open_device(argv[1],atoi(argv[2]));
}
if (uart<0) {
error("Open device failed !!\n");
return 0;
}else {
debug("Open Uart and set baud rate OK!!\n");
}
keep_run=1;
pid=fork();
if (pid) { // parent
input_command(0,uart);
debug("Exiting Tick's minicom\n");
}else { // child
pid = getppid();
read_from_uart(uart,1);
debug("Try to close uart\n");
debug("Result of close uart=%d\n",close(uart));
}
sprintf(buf,"kill -9 %d",pid);
system(buf);
}