2007年3月21日星期三
Build arm-linux-gdb
首先编译arm-linux-gdb
# cd /home/frank/temp/arm-debug
# tar xjvf gdb-6.6.tar.bz2
# mkdir build
# mkdir build-gdb
# cd build-gdb
# ../gdb-6.6/configuration --target=$TARGET --prefix=/home/frank/temp/arm-debug/build
# make
# make install
加入arm-linux环境变量, 将会出现错误
make[2]: Entering directory `/home/frank/temp/arm-debug/gdb-6.6/readline'
rm -f readline.o
gcc -c -DHAVE_CONFIG_H arm-linux- -I. -I.././readline -DRL_LIBRARY_VERSION='"5.1"' -g -O2 readline.c
gcc: arm-linux-: No such file or directory
make[2]: *** [readline.o] Error 1
make[2]: Leaving directory `/home/frank/temp/arm-debug/gdb-6.6/readline'
make[1]: *** [all-readline] Error 2
make[1]: Leaving directory `/home/frank/temp/arm-debug/gdb-6.6'
make: *** [all] Error 2
[frank@aladdin gdb-6.6]$
环境变量设置为
#!/bin/sh
export PREFIX=/usr/local/arm/3.2.3
export TARGET=arm-linux
#export HOST=arm
export PATH=$HOME/cross-arm/cross_LR3615/arm-linux/bin:$PATH
export KERNEL_DIR=$(pwd)/svn_ipcam/ipcam/trunk/LR3615_BII/kernel/linux-2.4.26
export CROSS_COMPILE=arm-linux-
不设置arm-linux环境变量, 编译可以通过. 两种方式生成的Makefile是一样的
使用gdb-6.3调试arm中的core dump, 无法看到符号信息, 而gdb-6.6版本是可以的
需要查看是哪个环境变量导致的问题
逐个加入环境变量, 运行make clean; make都可以编译通过, 由此推断出是在configuration时出的问题
检查readline/Makefile(设置环境变量时), 里面有
DEFS = -DHAVE_CONFIG_H arm-linux-
在设置环境变量之前做configuration, readline/Makefile内容为:
DEFS = @DEFS@ @CROSS_COMPILE@
LOCAL_DEFS = @LOCAL_DEFS@
由此可见是环境变量CROSS_COMPILE导致的问题
将export CROSS_COMPILE=arm-linux-注释掉, 重新设置环境变量, 再运行configuration
# ./configuration --target=$TARGET --prefix=/home/frank/test/arm-debug/build
# make
即可编译成功
总结:
编译arm版本gdb时, 不要加CROSS_COMPILE环境变量, 否则编译时会出现"gcc: arm-linux-: No such file or directory"错误.
接下来编译gdbserver
# cd /home/frank/temp/arm-debug
# cd build
# mkdir arm-linux
# cd ../../
# mkdir build_gdbserver
# cd build_gdbserver
# CC=arm-linux-gcc ../gdb-6.6/gdb/gdbserver/configure --host=$TARGET --prefix=/home/frank/temp/arm-debug/build/arm-linux
# make
# make install
然后将build目录下的东东copy到tools chain即可
# cd build
# find ./ -mount -print | cpio -pdm $PREFIX
在使用gdb时, 最好使用LD选项最好使用-static选项, 用静态链接的方式生成可执行文件, 否则在gdb中无法看到符号信息.
POXIS Thread
struct sockets {
int local;
FILE *in, *out;
};{
struct sockets s;
s.local = 1;
s.in = stdin;
s.out = stdout;pthread_create(&p, NULL, roll_dice, (void *) &s);
}
pthread_create() 将接受一个 void * 类型的参数,这个参数会被传到线程开始执行的那个函数中去。这样允许您创建一个任意复杂的数据结构,并将它作为一个指针传送给需要在这个数据结构上进行操作的线程。线程函数对参数的处理http://www.ibm.com/developerworks/cn/linux/l-pthred/index.html
/* read dice on standard input, write results on standard output */
void *roll_dice(void *v) {
struct sockets *s = v;
char inbuf[512];
/* think globally, program defensively */
if (!s || !s->out || !s->in)
return NULL;
fprintf(s->out, "enter die rolls, or q to quit\n");
...
}
pthreads 的基本用法
pthread_exit 线程终止
#include
void pthread_exit(void *value_ptr);
pthread_exit()函数将终止调用线程, 并使value_ptr值对任何与结束的线程成功结合(的线程)可用. 任何取消清除的已经压入并还没有压出的处理将以与压入相反的顺序压出并执行. 在所有取消清除的操作执行完毕后, 如果线程还有任何线程特定的数据, 相应的销毁函数将以不确定的顺序被调用. 线程终止并不释放任何应用程序可见进程资源, 包括, 但不仅仅是, 互斥和文件描述符, 它也不会执行任何进程级的清除操作, 包括, 但不限于, 调用任何可能退出的atexit()函数.
调用pthread_exit()的一个应用是当一个除了在第一次在main()调用的线程从用于创建它的起始程序中返回. 函数的返回值应用于线程的退出状态.
pthread_exit()如果从取消清除操作或作为隐式或显式的调用结果的销毁函数中调用, 其行为是不明确的.
在一个线程终止后, 线程内部的本地(自动)变量获取的结果是不明确的. 这样, 参考退出线程的本地变量不能作为pthread_exit() value_ptr参数值使用.
进程应该在最后一个线程终止后以带有0退出状态退出. 这种行为就像在线程终止时使用带有zero参数值的exit().
pthread_exit()--Terminate Calling Thread
Syntax: #includeThreadsafe: Yes Signal Safe: No |
The pthread_exit() function terminates the calling thread, making its exit status available to any waiting threads. Normally, a thread terminates by returning from the start routine that was specified in the pthread_create() call which started it. An implicit call to pthread_exit() occurs when any thread returns from its start routine. (With the exception of the initial thread, at which time an implicit call to exit() occurs). The pthread_exit() function provides an interface similar to exit() but on a per-thread basis.
Note that in the OS/400 implementation of threads, the initial thread is special. Termination of the initial thread by pthread_exit() or any thread termination mechanism terminates the entire process.
The following activities occur in this order when a thread terminates by a return from its start routine or pthread_exit() or thread cancellation:
- Any cancellation cleanup handlers that have been pushed and not popped will be executed in reverse order with cancellation disabled.
- Data destructors are called for any thread specific data entries that have a non NULL value for both the value and the destructor.
- The thread terminates.
- Thread termination may possibly cause the system to run OS/400 cancel handlers (registered with the #pragma cancel_handler directive), or C++ destructors for automatic objects.
- If thread termination is occurring in the initial thread, it will cause the system to terminate all other threads, then run C++ static object destructors, activation group cleanup routines and atexit() functions.
- Any mutexes that are held by a thread that terminates, become `abandoned' and are no longer valid. Subsequent calls by other threads that attempt to acquire the abandoned mutex though pthread_mutex_lock() will deadlock. Subsequent calls by other threads that attempt to acquire the abandoned mutex through pthread_mutex_trylock() will return EBUSY.
- No release of any application visible process resources occur. This includes but is not limited to mutexes, file descriptors, or any process level cleanup actions.
Do not call pthread_exit() from a cancellation cleanup handler or destructor function that was called as a result of either an implicit or explicit call to pthread_exit(). If pthread_exit() is called from a cancellation cleanup handler, the new invocation of pthread_exit() will continue cancellation cleanup processing using the next cancellation cleanup handler that was pushed. If pthread_exit() is called from a data destructor, the new invocation of pthread_exit() will skip all subsequent calls to any data destructors (regardless of the number of destructor iterations that have completed), and terminate the thread.
Cleanup handlers and data destructors are not called when the application calls exit() or abort() or otherwise terminates the process. Cleanup handlers and data destructors are not called when a thread terminates by any proprietary OS/400 mechanism other than the Pthread interfaces.
The meaning of the status parameter is determined by the application except for the following conditions:
- When the thread has been canceled using pthread_cancel(), the exit status of PTHREAD_CANCELED will be made available.
- When the thread has been terminated as a result of an unhandled OS/400 exception, operator intervention or other proprietary OS/400 mechanism, the exit status of PTHREAD_EXCEPTION_NP will be made available.
No address error checking is done on the status parameter. Do not call pthread_exit() with, or return the address of, a variable in a threads automatic storage. This storage will be unavailable after the thread terminates.
Note: If pthread_exit() is called by application code after step 3 in the above list, pthread_exit() will fail with the CPF1F81 exception. This indicates that the thread is already considered terminated by the system, and pthread_exit() cannot continue. If your code does not handle this exception, it will appear as if the call to pthread_exit() was successful.
Authorities and Locks
None.
Parameters
- status
- (Input) exit status of the thread
Return Value
pthread_exit() does not return.
Error Conditions
None.
Related Information
Core Dump
Core Dump?!
何谓 core?- 在使用半导体作为内存的材料前,人类是利用线圈当作内存的材料(发明 者为王安),线圈就叫作 core ,用线圈做的内存就叫作 core memory。如今 ,半导体工业澎勃发展,已经没有人用 core memory 了,不过,在许多情况下, 人们还是把记忆体叫作 core 。
- 我们在开发(或使用)一个程序时,最怕的就是程序莫明其妙地当掉。虽然系 统没事,但我们下次仍可能遇到相同的问题。于是这时操作系统就会把程序当掉 时的内存内容 dump 出来(现在通常是写在一个叫 core 的 file 里面),让 我们或是 debugger 做为参考。这个动作就叫作 core dump。
- 前面说过,在程序当掉时出错。在 C/C++语言中,最常发生错误的地方就是指 针有问题。您可以利用 core 文件和 debugger 把错误找出来(要怎麽在 debugger 中使用 core 文件?man 一下 gdb 吧!)。
- 如果你不会、不能、不需要修改程序,那就放心地把它删除了吧!
- 如果用的是tcsh的话, 以试著在 .tcshrc 里加一行:
limit coredumpsize 0
如果用的是bash的话, 在/etc/profile里加上(或者修改)一条:
ulimit -c 0
gdb -c core, 进去後打 where, 就可以 show 出你是在程序哪一行当掉的, 还有在当掉时在哪个 function 里, 这个 function 是被哪个 function 所 call 的, 而这个 function 又是被哪个 function 所 call 的.... 一直到 main()
由这个信息, 可以找出五六成的 bug........ 屡试不爽
但, 先决条件, 当你在 compile 时必须把 debug information 的选项打开 不然, 就会出现一大堆你看不懂的东西,而不是你喜欢的源程序。
在编程的过程中,不可避免地会有一误操作,当然这些误操作编译器是不知道的,你运行gcc命令编译程序,编译通过了生成可运行程序了。这个程序虽然可以运行了,但可能是不正常的。
比如有的程序只顾着打开文件却不关闭文件,因为操作系统会为每个打开的文件分配一个句柄(file descriptor),这样的程序长久运行下去必然导致打开的文件句柄超出系统资源限制。超出系统资源限制的后果可能不仅仅影响到当前用户,整个系统都可能会受影响。
又比如有些程序,比如下面的代码:
| #include #include #include #include int main() { while(1) if(fork() <> |
作为一个初学者,编程过程中发生这些失误再所难免,但如果因为这样的错误就导致我们要不断重新启动计算机,甚至不小心丢失一些还未来得及保存的数据,那就可惜了。
Linux系统中提供了一些保护机制,我们可以避免不必要的麻烦。其中bash提供这样一个ulimit命令就可以用来帮助我们实现资源配置的目的。查看bash手册可以看到这些:
| ulimit [-SHacdefilmnpqrstuvx [limit]] Provides control over the resources available to the shell and to processes started by it, on systems that allow such con‐ trol. The -H and -S options specify that the hard or soft limit is set for the given resource. A hard limit cannot be increased once it is set; a soft limit may be increased up to the value of the hard limit. If neither -H nor -S is speci‐ fied, both the soft and hard limits are set. The value of limit can be a number in the unit specified for the resource or one of the special values hard, soft, or unlimited, which stand for the current hard limit, the current soft limit, and no limit, respectively. If limit is omitted, the current value of the soft limit of the resource is printed, unless the -H option is given. When more than one resource is specified, the limit name and unit are printed before the value. Other options are interpreted as follows: -a All current limits are reported -c The maximum size of core files created -d The maximum size of a process’s data segment -e The maximum scheduling priority (‘nice’) -f The maximum size of files created by the shell -i The maximum number of pending signals -l The maximum size that may be locked into memory -m The maximum resident set size -n The maximum number of open file descriptors (most systems do not allow this value to be set) -p The pipe size in 512-byte blocks (this may not be set) -q The maximum number of bytes in POSIX message queues -r The maximum rt priority -s The maximum stack size -t The maximum amount of cpu time in seconds -u The maximum number of processes available to a single user -v The maximum amount of virtual memory available to the shell -x The maximum number of file locks If limit is given, it is the new value of the specified resource (the -a option is display only). If no option is given, then -f is assumed. Values are in 1024-byte increments, except for -t, which is in seconds, -p, which is in units of 512-byte blocks, and -n and -u, which are unscaled values. The return status is 0 unless an invalid option or argument is supplied, or an error occurs while setting a new limit. |
你可以用下列命令试一下:
ulimit -a
这个命令显示所有当前资源限制情况。
限制有两种,一种是软限制(soft limit),另一种是硬限制(hard limit)。比如:
ulimit -S -f 1024
这个命令将限制当前shell创建的文件大小为1024K,所以你可能没办法产生一个超过1M的文件。但这是软限制。
又比如:
ulimit -H -u 100
这个命令将设置系统中当前用户能够开启的进程最多为100个,所以这一设置上面那个fork程序就不会让系统死机了。
软限制是可以突破的,而硬限制是不能突破的,软限制还可以突破到硬限制设定的值来。
用ulimit的另外一个好处就是设置系统资源以满足进行特定测试。
比如我们想要调试程序,可能有些系统默认是限制产生core dump文件的,而我们知道,core dump文件是我们调试程序的一个很有用的帮助文件,根据core dump文件提供的信息,我们可以比较快地定位到程序的bug。
如果用命令:
ulimit -c
看到的是0,则说明系统限制了产生core dump,我们可以设定一个文件大小以产生core dump文件。比如:
ulimit -c 1024
将设置允许产生的core dump文件最大为1024K
当然我们也可以设置为
ulimit -c unlimited
表示不限制产生的core dump文件的大小。