Linux的环境变量LD_DEBUG调试so的加载

一个稍微有经验的Linux程序员都知道使用LD_LIBRARY_PATH 来临时设置加载器搜索动态链接库so的路径顺序。但另一个不为人知的环境变量是LD_DEBUG。这个变量可以提供非常详细的加载动态链接库的信息。

 

可以把LD_DEBUG设成以下值:

export LD_DEBUG=files     # 显示库的依赖性和加载的顺序

export LD_DEBUG=bindings  # 符号绑定

export LD_DEBUG=libs   # 显示加载器查找库时使用的路径的顺序

export LD_DEBUG=versions  # 版本依赖性

export LD_DEBUG=help  # LD_DEBUG的帮助信息

 

试一下把LD_DEBUG设成以上值之一,再随便运行一个程序试试。

一个试验:

root@vicarious:/home/kamus/projs/horoscope/bins# export LD_DEBUG=libs

root@vicarious:/home/kamus/projs/horoscope/bins# vim my.conf

     24360:   find library=libm.so.6 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libm.so.6

     24360:

     24360:   find library=libtinfo.so.5 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libtinfo.so.5

     24360:

     24360:   find library=libselinux.so.1 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libselinux.so.1

     24360:

     24360:   find library=libacl.so.1 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libacl.so.1

     24360:

     24360:   find library=libgpm.so.2 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/usr/lib/x86_64-linux-gnu/libgpm.so.2

     24360:

     24360:   find library=libc.so.6 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libc.so.6

     24360:

     24360:   find library=libdl.so.2 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libdl.so.2

     24360:

     24360:   find library=libattr.so.1 [0]; searching

     24360:   search cache=/etc/ld.so.cache

     24360:     trying file=/lib/x86_64-linux-gnu/libattr.so.1

copyright ykyi.net

运行loadlib()提示attempt to call global ‘loadlib’ (a nil value)

2009年的时候用过lua,当时在windows上写金山急救箱的恶意软件库引擎。

时隔多年,又要玩一把lua. 重拾lua,在lua控制台用loadlib载入动态链接库时出错:

> loadlib("libhello.so", "*")
stdin:1: attempt to call global 'loadlib' (a nil value)
stack traceback:
    stdin:1: in main chunk
    [C]: in ?

Lua表示在全局域中没有loadlib。google后发现两种解决方案:

第一种认为这种错误是因为没有把loadlib编译进lua中,需要改makefile.如此贴的楼主所述: http://lua-users.org/lists/lua-l/2009-02/msg00463.html

第二种是在csdn上的贴子,要改lua的源文件中的一个define,实际上这种方法也是可以在makefile中define一个变量的。

不过!!!

问题其实更简单,不需要改什么makefile文件:

http://lua-users.org/lists/lua-l/2009-02/msg00466.html

lua在5.0以后,loadlib已经不在全局域中了,loadlib在package名字空间中了。

这样就好了:

package.loadlib("libhello.so", "*")

实际上,loadlib是一个底层的函数。不像require,loadlib不在path里进行查找,也不自动添加文件名后缀。这个函数在某些平台上不被支持,因为ANSI并没有要求支持动态链接库。

copyright ykyi.net

什么是0MQ或ØMQ,或ZeroMQ

ØMQ或者拼写成ZeroMQ,0MQ,是一个高性能异步消息队列库,旨在在分布式可扩展的并行程序中使用。它提供了一个消息队列,但不像面向消息的中间件,即使没有特定的消息经纪人(Message Broker),0MQ也能正常工作。

 

这个库在TCP的基础上开发,但能获得比TCP更高的性能,更不用说它提供了各种安全机制和分布式易扩展的特性。

 

0MQ的API和传统的socket很像。OMQ中的socket描述了一个,多个终端之间的多对多的连接。0MQ还有一个消息模式的概念。基本的0MQ消息模式有:

Request-reply:

用来连接一组客户端和一组服务。这个模式是一个远程过程调用RPC,和多任务分发模式。

Publish-subscribe:

用来连接一组发行端和一组接收端。这是一个数据分发模式。

Push-Pull(Pipeline)

用扇入/扇出模式连接很多结点,通常要分好几个步骤。这是一个多任务并行分布和收集的模式。

Exclusive Pair:

用排它模式连组两个socket。这其实是一个为特殊需求准备的高级底层模式。

 

每一种模式定义了一个对应的网络拓扑。Request-reply模式定义了所谓的”服务总线”,publish-subscribe定义了数据分发树,push-pull定义了并行管道。这样模式都被精心设计,使他们可以在互联网上被无限扩展。

 

不想译了,。更多内容见wikipedia。kamuszhou@qq.com 腾讯视频广告

copyright ykyi.net

Git 的M,T,D,A,U标志是什么意思

在使用git checkout , git status,或git diff files时会出现奇怪的标志。如M,T,D,A,R,U等等。

如:

# git checkout master

M     cpp-iniparser

文件cpp-iniparser前面有个M. git的这些奇怪标志是什么意思呢。

A: 增加的文件.

C: 文件的一个新拷贝.

D: 删除的一个文件.

M: 文件的内容或者mode被修改了.

R: 文件名被修改了。

T: 文件的类型被修改了。

U: 文件没有被合并(你需要完成合并才能进行提交)

X: 未知状态。(很可能是遇到git的bug了,你可以向git提交bug report)

在git diff-files的手册man git diff-files中可以查到这些标志的说明。

这些状态标志在git的源代码的diff.h文件中被定义。

copyright ykyi.net

使用Git的submodule功能管理第三方库

用Git的Submodule功能来管理代码中使用的其它库,还是满方便的。主要用到三个命令:

Git submodule add, git submodule init, git submodule update.

git submodule init to initialize your local configuration file and git submodule update to fetch all the data from that project and check out the appropriate commit listed in your superproject.

还有两个查看相关信息的命令git submodule summary,和 git submodule status.

Git的submodule功能带来的好处和坏处都很多,网上有大量的贴子反对使用git submodule。

我觉有限制地,在以下场景用git submodule管理第三方库的代码还是很不错。

1.    你使用的第三方库更新非常慢,甚至不更新,它的接口很稳定。比如:管理vim的插件们。

2.    第三方库以比较固定的周期更新。于是,过一段时间再把上游的代码拉到submodule上来。

3.    第三方库虽然更新很快,但我过一段时间才拉取上游代码也无所谓。

如果单开一个git clone管理第三方库,与自己的项目平行,当然也是可以的。但这样有个问题是,别人git clone了你的项目,还需要再git clone一次你的项目依赖的项目,并放在适当的相对路径上。而使用git submodule *时,你的项目和你依赖的库是层级关系,有条理得多。

 

还有一种方式是把第三方库的代码合并到自己的代码中。这样做的坏处是显而易见的,如果你要合并上游代码的FIX或功能加强,都非常的麻烦。大多数人是不会去做这个同步的,于是代码会被手动复制,越来越多的细微改动分散在各个不同的项目的相同/相近代码中。一片混乱….

使用Git Submodule时忽略Submodule的改动:

如果submodule中有生成新文件。在父工程(superproject)中用git status,就总会提醒你git submodule子模块有还没被跟踪的文件。

比如:一次make会生成很多.o,.dep文件。比如用git submodule管理vim插件会生成各种临时文件。你不想让git status提醒你,这多么烦人啊。

如下,git status总提醒我cpp-iniparser子模块有未跟踪的文件:

root@vicarious:/home/kamus/projs/horoscope# git status
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>…" to update what will be committed)
#   (use "git checkout — <file>…" to discard changes in working directory)
#   (commit or discard the untracked or modified content in submodules)
#
#    modified:   configuration.cpp
#    modified:   configuration.h
#    modified:   cpp-iniparser (untracked content)

如何让git忽略到这个提醒呢,解决方法是编辑父工程中的.gitmodules文件。加入 ignore = dirty。如下:

[submodule “cpp-iniparser”]
    path = cpp-iniparser
    url = https://github.com/zausiu/cpp-iniparser
    ignore = dirty

 

git clone的代码里面有submodule,目录是空的。怎么clone子模块submodule的代码

对于git 1.6.5以后的版本,使用clone的–recursive,如下:

git clone –recursive git://github.com/foo/bar.git

对于老旧的git,可以使用git submodule init和git submodule update

比如:

git clone git://github.com/foo/bar.git

// 此处可以要先cd到子模块的目录,较新的git则不需要cd
git submodule init
git submodule update

git submodule status显示的HASH代码前的横杠-是什么意思

表示对应的子模块submodule还没有下载到本地。

git怎么删除一个子模块submodule

step 1: 删除.gitmodules文件中子模块的对应项

step 2: 删除.git/config文件中子模块的对应项

step 3:git rm …

git submoduler的160000什么意思?

当在包含有submodule的父工程中git commit以后,会有类似create mode 160000 submoduleName 的提示,这个160000的意思是:this is a special mode in git that basically means you're recording a commit as a commit as a directory entry rather than a subdirectory or a file.

其它有用的git submodule命令:

git diff –submodule: you can see that the submodule was updated and get a list of commits that were added to it

git submodule update –remote means: git goes into your submodules and fetch(git fetch) and update(git merge origin/master) for you.

git submodule update –remote –merge or –rebase

git submodule foreach 'git stash'; git submodule foreach 'git checkout -b featureA'

使用Git Submodules需要注意的地方:GOTCHA

1.    如果你修改了submodule的代码,那必须先commit submodule的这些修改,再到父工程(superproject)中提交commit。

2.    Git 在父工程中用git update会覆盖子模块的未提交的更新。

3.    如果手动修改了父工程目录下的.gitmodules文件,那么需要用git submodule sync来更新.git/config文件中的配置。

4. When run git submodule update, If your forget the –rebase or –merge. Git will just update the submodule to whatever is on the server and reset your project to a detached HEAD state.

copyright ykyi.net

HTTP中的HEAD方法是什么

HTTP中的HEAD方法和GET方法是一样的,除了服务器在响应HEAD方法时不充许活加消息体(message body).服务器用来回复HEAD的响应信息中,在HTTP头部中的元信息需要跟回复GET时一样。这样,一个客户就可以通过HEAD来得到某资源的源信息,而不需要把整个资源都传输一次。

HEAD方法通常被用来测试超链接的可达,和资源是否已经更新。

HEAD方法的主要应用场景是检索资源的元信息meta infomation。用getResponseHeaders()函数可以得到HTTP的头部~

copyright ykyi.net

configure –prefix 和 make install DESTDIR= 还有make install prefix 什么区别

./configure –prefix=*

确定了程序会被包装到哪里,以及,程序将在什么位置搜寻运行需要用到的相关的文件。如果你在一台机器上编译,然后仍然在这台机器上运行,那使用configure –prefix就是你想要的了。

 

make install DESTDIR=*

把程序安装到一个临时用的目录,这个目录不是程序以后将要运行的目录。例如,这个功能被deb包的打包人员使用。打包人员使用此功能时,并不真正把程序安装到–prefix指定的目录下。因为他可能已经安装了不同的版本,他不想搞乱他的环境,或者他没有boot权限,没有办法把程序安装到/bin,/sbin之类目录。 –prefix=/usr,让程序运行时认为被安装在/usr,然后make install DESTDIR=debian/tmp则实际把程序安装到debian/tmp。

 

make install prefix=/foo/bar/baz

和 make install DESTDIR的区别在于,前者不会创建prefix后面指定的所有目录层级,而DESTDIR会。

例如:

./configure –prefix=usr/local && make && sudo make install prefix=/usr/local/stow/foo 会把程序安装在/usr/local/stow/bin目录下。

而: make install DESTDIR=/usr/local/stow/foo,则把程序安装在/usr/local/stow/foo/usr/local/bin下面。

copyright ykyi.net

抓包程序的一些分享

昨晚同白总和adden提到抓包的问题。因为写过相关的代码,遇到过抓包的各种各样的坑,此文分享一些相关的经验。

 

1. Linux cooked capture

在用tcpdump或wireshark看数据包时,有时会看到数据链路层的的包头称为Linux cooked capture。这不是一个真实的包头,当用tcpdump指定从所有网络介质 -i any 抓包时,所有抓到的包的数据链路层被换成了Linux cooked capture。在wireshark官方网站对Linux cooked capture的解释中: 这是一个在linux上被libpcap抓包库使用的“假协议”(pseudo-protocal),当从“any”设备在抓包,或者本地的数据链路层包头无效时被使用。更多,见http://wiki.wireshark.org/SLL

 

2. IP over IP tunnel

wikipedia的示例图显示IP tunnel上的包的结构是:

但实战中用libpcap库从我们的线上机的IP隧道抓包时,pcap_loop或pcap_dispatch或pcap_next函数返回的数据包只有Inner IP header + IP payload,没有Outer IP headr,也没链路层的头部。多么幸运啊!

 

3. 混乱的RAW_SOCKET,PF_PACKET协议族

这不是工业标准定义的神秘领域,非常之混乱,谨慎进入。如果要写这方面的socket,可供参考。个人经验,用linux原生的socket抓包时,socket()的三的参数如下组合时的神奇效果.

     

        _recv_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));

        从此socket中读所有的IP包,返回的IP包没有链路层包头,因为第二个参数是SOCK_DGRAM,链路层包头返回时被去掉。第三个参数指定的是IP包。奇怪的是,如果出站的IP包的目的地址不是本机,则出站的IP包不会被抓到。

       

        _recv_fd = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_IP));

        和上一个socket的区别是,这个会返回链路层包头。和上一个socket一样,同样只能装到部分出站的包。

      

            _recv_fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);

        这行代码只可以读入站的包,抓不到出站的包。

 

            _recv_fd = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_ALL));

        这行代码可以抓到所有出站,入站的包,数据链路层包头也被返回。

 

4. 外网进来的IP包有可能很大。

N多年前一般的路由的MTU只有1K多,意味着4K大小的IP会被切成小IP包。现在的网络环境与几年前确实大大提高。从外网入来的IP包会大过4096,当时写程序时放IP包的buffer大小为4096,觉得应该无压力,结果观察到程序崩溃,后定位到是放IP包的缓冲区溢出。后来改成8192,暂时没问题。

copyright ykyi.net

为什么dump生成core文件大小是0

今天程序崩溃了,但是生成的core文件大小是0.

用ulimit -c 查看生成core文件的大小限制是无限unlimited.

也不是磁盘大小和写入权限的问题。

但究竟是什么问题呢?

捣了半天终于搞明白,原来是文件系统造成的。

我是在vmware的虚拟机的debian linux上运行程序,文件系统用的是从host机windows 7挂载到/mnt/hgfs的windows的NTFS文件系统。

后来我把程序转移动linux自己的文件系统,崩溃的时候就生成正常的core dump文件了。

copyright ykyi.net

CDT调试中的追踪点和断点有什么区别。

追踪点(Tracepoint)被当成断点(breakpoint)的一种,但有两个不同点需要注意:

1. 当一个追踪点在一个调试会话中被创建时,它并不种入到二进制代码中,直到用户显式地开始追踪实验。这意味着,创建/修改/删除追踪点并不影响程序,直到追踪真正开始。

2. 简单的创建一个追踪点并不是非常有价值,因为它默认不会收集任何信息。重要的是,把操作(Actions)添加到Tracepoint,这样tracepoint被触发的时候,前面自定义的Action就大有用处了。

来自CDT官网的原文:

Create Tracepoints

Tracepoints are handled as a type of breakpoint. There are two differences to note:

  1. When a tracepoint is created in a debug session, it is not actually planted in the binary code until the user explicitly starts the tracing experiment. This means that creating/modifying/deleting tracepoints does not affect the program until tracing is actually started.
  2. Simply creating a Tracepoint has very limited value as it won't collect any information by default. It is important to add Actions to the Tracepoint to tell it what to do. This will be explained below.

copyright ykyi.net