Skip to content

Commit 1371e2a

Browse files
committed
0.2 (Revised Draft)
1 parent 21d3006 commit 1371e2a

28 files changed

+349
-267
lines changed

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
Linux Development FAQs
22
=======
33

4-
本书介绍了Linux平台下应用开发常用的知识点,结合作者在之前工作遇到的问题及其解决方法。
5-
本书的描述假定读者有一定的Linux开发基础与经验。希望能对读者学习和工作有参考价值。
6-
本书将详细讲述了编译,连接,进程的运行时环境;介绍了进程调试的方法;介绍了C语言开发中可能遇到的内存相关的问题与解决方法、工具。
7-
介绍了SHELL与应用开发中常见的与系统管理、网络等相关的内容。介绍了SYBASE等数据库在开发中需要注意的事项等等内容。
8-
本书将持续更新。
4+
本书以解决具体问题的形式讲述了Linux环境中应用程序开发中的相关知识和工具:包括编译、连接,进程的运行时环境;
5+
介绍了进程调试的方法;介绍了C语言开发中可能遇到的内存相关的问题与解决方法、工具;
6+
介绍了SHELL与应用开发中常见的与系统管理、网络等相关的内容;介绍了SYBASE等数据库在开发中需要注意的事项等内容。
7+
是作者在之前工作遇到的问题及解决办法的笔记与备忘录。
8+
99
需要说明的是本书是作者工作中的一些经验的总结,本书中参考了大量的资料。由于时间跨度较长等原因,很多资料没有一一注明原作者和出处,这里一并表示感谢。若有异议,请联系作者。
10+
本书的描述假定读者有一定的Linux开发基础与经验。希望能对读者学习和工作有参考价值。
1011

11-
VERSION: 0.1 (Draft)
12-
12+
本书将持续更新。
13+
Current VERSION: 0.2 (Revised Draft)

SUMMARY.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,12 @@
1010
* [第三方库](programming/lib.md)
1111
* [其它工具](programming/tools.md)
1212

13-
* [运行](runtime/README.md)
13+
* [运行与调试](runtime/README.md)
1414
* [环境](runtime/env.md)
1515
* [进程检查](runtime/pcheck.md)
1616
* [关于coredump](runtime/core.md)
17-
18-
* [调试](debug/README.md)
19-
* [gdb](debug/gdb.md)
20-
* [函数调用关系](debug/func.md)
17+
* [gdb](runtime/gdb.md)
18+
* [函数调用关系](runtime/func.md)
2119

2220
* [内存](memory/README.md)
2321
* [操作系统命令](memory/linux.md)

database/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# 简介
2+
本章介绍了数据库编程的知识。
3+
4+
主要是SYBASE ASE使用过程中的一些问题的记录。另外也介绍了Windows平台DB2预编译的方式和命令。

database/sybase.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
ct__string_extended_encryption: user api layer: internal common library error:
77
Client password encryption fails.
88
```
9-
问题是在 OCS-15_0的lib3p,将其 LD_LIBRARY_PATH下问题解决
9+
问题是在 OCS-15_0的lib3p,将其配置到LD_LIBRARY_PATH中问题解决
1010

1111
## 关于sybase的locale
1212
linux下 locale设置为 zh_CN.gbk后,sybase的 isql 报错

debug/README.md

Whitespace-only changes.

memory/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# 简介
2+
本章介绍Linux中与内存有关相关知识。
3+
4+
主要介绍Linux操作系统提供的内存相关命令;Glibc中提供的关于内存维护和检查的函数;以及第三方工具和库。

memory/glibc.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,32 +91,35 @@ int main()
9191
}
9292
```
9393
上面的代码编译会报错`warning: '__malloc_hook' is deprecated (declared at /usr/include/malloc.h:153) [-Wdeprecated-declarations]`
94-
因为其不适用与多线程的环境。若果在单线程环境使用该技术,可以仿照malloc的实现,
94+
因为其不适用与多线程的环境。
95+
若果在单线程环境使用该技术,可以仿照malloc的实现,
9596
利用`__builtin_return_address(0)`与`__libc_malloc`实现`__malloc_hook`的功能
9697
9798
## __libc_malloc等函数
9899
Glibc中malloc等函数实际上是调用了`__libc_malloc`等函数;
99-
后者可以用来实现自己的malloc以"重载"标准库中的malloc
100-
可以测试时使用,结合LD_PRELOAD等。
101-
需要注意的是free必须支持free(NULL)。否则程序可能尚未执行即coredump。
102-
使用`__libc_malloc`函数实现malloc,若其中需要读写文件不能使用C标准库函数,需要使用系统调用
100+
可以结合LD_PRELOAD用来实现自己的malloc以"重载"标准库中的malloc,可以测试时使用。
101+
需要注意的是
102+
* free必须支持free(NULL)。否则程序可能尚未执行即coredump。
103+
* 使用`__libc_malloc`函数实现malloc,若其中需要读写文件不能使用C标准库函数,需要使用`open`系统调用
103104
104105
## mallopt函数
105106
`MMAP_THRESHOLD`决定malloc时使用sbrt还是mmap
106107
设置内存分配参数,控制内存分配函数的行为
107108
108109
## mcheck、mtrace
109-
使用`mtrace`简单的进行内存泄漏检测,它hook malloc(), realloc(), memalign(), calloc() 和 free()
110+
可以使用`mtrace`简单的进行内存泄漏检测,mtrace hook malloc(), realloc(), memalign(), calloc() 和 free(),
110111
对分配和释放内存的操作进行配对检测,如果发现有内存泄漏的情况, 会记录导致内存泄漏的分配函数调用所在的位置,
111-
并将记录保存到环境变量 `MALLOC_TRACE` 指定的文件中,然后就可以使用 mtrace 命令来查看日志了。
112-
man mtrace
113-
info mtrace
114-
查阅`glic manual (info libc): Memory(Virtual Memory Allocation And Paging):Memory Allocation: Unconstrained Allocation: Heap Consistency Checking`
112+
并将记录保存到环境变量 `MALLOC_TRACE` 指定的文件中,然后就可以使用 mtrace 命令来查看日志了。
113+
`man mtrace`
114+
`info mtrace` 查阅`glic manual (info libc): Memory(Virtual Memory Allocation And Paging):Memory Allocation: Unconstrained Allocation: Heap Consistency Checking`
115115
注意使用mtrace函数必须在malloc等函数调用之前调用,需引用头文件`#include <mcheck.h>`
116116
另,可以`-lmcheck`连接`mcheck`库。
117-
查阅环境变量`MALLOC_CHECK_ `
117+
118+
环境变量`MALLOC_CHECK_ `提供了类似的功能。
118119
119120
120121
## libmemusage 统计内存使用
121-
glibc 自带了一个 libmemusage 的库,用于收集应用程序运行时的内存使用情况。使用起来很简单,只要在编译的时候添加 -lmemusage 即可。
122-
它使用 api hook 技术对 malloc, realloc,calloc和free 的调用进行监视,统计相应大小内存块的使用比率,并可给出简单的内存申请与释放的统计信息,可以用于简单的判断是否有内存泄漏。
122+
glibc 自带了一个 libmemusage 的库,用于收集应用程序运行时的内存使用情况。
123+
使用起来很简单,只要在编译的时候添加 `-lmemusage` 即可。
124+
它使用 api hook 技术对 malloc等的调用进行监视,统计相应大小内存块的使用比率,
125+
并可给出简单的内存申请与释放的统计信息,可以用于简单的判断是否有内存泄漏。

memory/lib.md

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
#检查内存的第三方库和工具
22

33
## Electric Fence检测内存越界操作
4-
Electric Fence 使用虚拟内存技术,在 malloc() 分配到的内存块的前后分别放置一个 不能访问的内存页
4+
Electric Fence 使用虚拟内存技术,在 malloc() 分配到的内存块的前后分别放置一个不能访问的内存页
55
当应用程序去读写这两个内存页时硬件会引发段错误。
66
* 安装(OpenSUSE中)
7-
```shell
7+
```bash
88
zypper install ElectricFence
99
rpm -ql ElectricFence
1010
```
1111
* 使用
12-
只要添加链接选项 -lefence 链接 libefence.so,它会在程序运行时预先加载 libefence.so Hook 对 malloc(…) 的调用。也可以不用编译程序而通过设置 PRE_LOAD=/usr/lib64/libefence.so 环境变量 来实现或者直接链接 /usr/lib64/libefence.a。默认情况下 Electric Fence 只会检测 读写越下边界和已释放的内存块的违规操作。Electric Fence 不能与其他 内存检测工具 或者内存分配器使用,因为内存检查工具一般都是通过 hook 内存分配函数来实现内存检测的。
12+
* 添加链接选项 -lefence 链接 libefence.so,它会在程序运行时预先加载 libefence.so Hook 对 malloc等的调用。
13+
* 不用编译程序而通过设置 PRE_LOAD=/usr/lib64/libefence.so 环境变量
14+
* 直接链接 /usr/lib64/libefence.a
15+
* 默认情况下 Electric Fence 只会检测读写越下边界和已释放的内存块的违规操作
16+
* Electric Fence 不能与其他内存检测工具或者内存分配器使用
1317
* 环境变量
1418
* EF_ALIGNMENT 变量控制分配到的内存块的对齐大小,值越小越严格。
1519
* EF_PROTECT_BELOW=1 时在内存块的之前也添加一个无法访问的内存页。检查访问越过内存块上边界的情况。
@@ -18,12 +22,12 @@ rpm -ql ElectricFence
1822
* EF_FILL,设置指定的值使 Electric Fence 在分配内存之后 将内存块初始化为此值。
1923

2024
## DUMA 检测内存违规访问和内存泄漏
21-
D.U.M.A 的全称是 Detect Unintended Memory Access,它是 Electric Fence 的加强版
22-
能定位C++程序内存非法访问的位置,与内存泄露。
23-
为了收集内存分配的语句所在的位置,DUMA 需要对 malloc() 等函数进行“Hook”,这是用宏实现的,
24-
所以需要包含头文件`#include <duma.h>`(对C++程序`#include <dumapp.h>`)。并链接 libduma.a 和 pthread 库。例如:
25+
D.U.M.A(Detect Unintended Memory Access)是 Electric Fence 的加强版, 能定位C++程序内存非法访问的位置与内存泄露。
26+
为了收集内存分配的语句所在的位置,DUMA 需要对 malloc() 等函数进行“Hook”,这是用宏实现的.
27+
* 需要包含头文件`#include <duma.h>`(对C++程序`#include <dumapp.h>`
28+
* 需要链接 libduma.a 和 pthread 库。
2529
`g++ -g -O0 heap-corruption.cc -o heapC -Wl,-Bstatic,-lduma -Wl,-Bdynamic –pthread`
26-
* 环境变量
30+
* 环境变量
2731
DUMA和Electric Fence一样,同样支持通过变量来控制其行为,只不过比Electric Fence要多。常用如下:
2832
* DUMA_ALIGNMENT :对应 EF_ALIGNMENT。
2933
* DUMA_PROTECT_BELOW:对应 EF_PROTECT_BELOW。
@@ -58,7 +62,7 @@ DUMA和Electric Fence一样,同样支持通过变量来控制其行为,只
5862
## 关于 dmalloc的一些使用经验
5963
* 安装
6064
下载dmalloc源代码,执行
61-
```
65+
```bash
6266
./configure --enable-threads
6367
make
6468
make install
@@ -67,7 +71,7 @@ make install
6771
* dmalloc的源代码中有文件settings.dist,其中有一些宏定义。 例如,将 ALLOW_FREE_NULL_MESSAGE 设置为 0 可以不输出 WARNING .... FREE 0 .... 的警告
6872
* 把dmalloc安装后的lib路径加入到/etc/ld.so.conf中,然后执行ldconfig -v
6973
* 在.bashrc, .profile或.zshrc文件中添加
70-
```shell
74+
```bash
7175
function dmalloc { eval `/usr/local/bin/dmalloc -b $*`; }
7276
```
7377
* 使用
@@ -93,8 +97,36 @@ dmalloc_log_changed(mark,1,0,1);
9397
必须在 #include <stdlib.h> 之后 #include "dmalloc.h" 否则编译会报错
9498

9599
* 根据结果分析数据
96-
若在logfile中出现not freed: '0x400177c8|s1047' (20 bytes) from 'ra=0x0x400618' 则说明程序存在内存泄露;
97-
定位内存泄露代码行数(使用命令readelf nm ldd)
100+
若在logfile中出现
101+
```
102+
not freed: '0x400177c8|s1047' (20 bytes) from 'ra=0x0x400618'
103+
```
104+
则说明程序存在内存泄露;
105+
98106
备注:
99-
环境变量 DMALLOC_OPTIONS=log=/path/logfile,debug=0x.......
100-
使用 `dmalloc -DV` 可以显示各个参数的意义
107+
* 环境变量 DMALLOC_OPTIONS=log=/path/logfile,debug=0x.......
108+
* 使用 `dmalloc -DV` 可以显示各个参数的意义
109+
110+
## 定位内存泄露代码所在行
111+
使用**addr2line**
112+
```bash
113+
#/bin/sh
114+
loc=$1
115+
echo "loc=$loc"
116+
lib=$(echo $loc | awk -F[+\(\)] '{print $1}')
117+
func=$(echo $loc | awk -F[+\(\)] '{print $2}')
118+
offset=$(echo $loc | awk -F[+\(\)] '{print $3}')
119+
echo "lib=$lib"
120+
echo "func=$func"
121+
echo "offset=$offset"
122+
echo "FIND FUNC $(nm $lib | grep -w $func)"
123+
base=$(nm $lib | grep -w $func | awk '{print $1}')
124+
echo $base
125+
let b=0x$base
126+
let o=offset
127+
let x=b+o-1
128+
echo $x
129+
addr=$(echo "obase=16;$x" | bc)
130+
echo $addr
131+
addr2line -e $lib 0x$addr
132+
```

memory/linux.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
# Linux提供的内存相关的技术
1+
# Linux中内存相关命令与配置
22

33
## 查看进程内存使用情况
4-
* top命令
5-
`top -d 1 -p pid [,pid ...] //设置为delay 1s,默认是delay 3s`
4+
* `top -d 1 -p pid [,pid ...]` //设置为delay 1s,默认是delay 3s
65
如果想根据内存使用量进行排序,可以shift + m(Sort by memory usage)
76
* pmap
87
* ps
@@ -23,22 +22,25 @@ optimistic memory allocation stategy
2322
* /proc/_pid_/oom_adj
2423
* oom_adj的值越大,该进程被系统选中终止的可能就越高,当oom_adj=-17时oom_score将变为0
2524

26-
Linux 提供了这样一个参数min_free_kbytes,用来确定系统开始回收内存的阈值,控制系统的空闲内存。值越高,内核越早开始回收内存,空闲内存越高。
25+
Linux 提供了这样一个参数min_free_kbytes,用来确定系统开始回收内存的阈值,控制系统的空闲内存。
26+
值越高,内核越早开始回收内存,空闲内存越高。
2727
`echo 963840 > /proc/sys/vm/min_free_kbytes`
2828

29-
可以通过修改内核参数禁止OOM机制
29+
可以通过修改内核参数禁止OOM机制
3030
`sysctl -w vm.panic_on_oom=1`
31-
`vm.panic_on_oom = 1 //1表示关闭,默认为0表示开启OOM`
31+
`vm.panic_on_oom = 1` //1表示关闭,默认为0表示开启OOM
3232
`sysctl -p`
3333

3434
## 关于free
35-
free -m的结果可以用下图描述:
36-
37-
![free -m](./free.png "free -m")
38-
35+
`Memory=Used+Free+Buffer+Cache`
36+
free -m的结果可以用下面的公式表示
37+
```
38+
Mem: used=Used+Buffer+Cache / free=Free
39+
-/+buffers/cache: used=Used/free=Free+Buffer+Cache
40+
```
3941

4042
## 清空cache:
41-
`sudo sysctl vm.drop_caches=3 释放buffer+cache`
43+
`sudo sysctl vm.drop_caches=3 `释放buffer+cache
4244
`echo 1 > /proc/sys/vm/drop_caches`
4345

4446
## 内核空间的内存

misc/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# 简介
2+
本章介绍了桌面或虚拟机使用中一些配置和问题及解决。

programming/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
# Summary
2-
本章将介绍GCC编译相关知识。
1+
# 简介
2+
本章主要介绍Linux环境下GCC的使用,并总结了编译链接过程中常见的问题和解决方法;
3+
介绍了信号与网络等应用程序开发中经常用到的系统相关技术与注意事项;介绍对开发有帮助的相关的第三库与工具。

programming/check.md

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
#目标文件与可执行文件的属性
22

3-
## 查看程序或库的信息
4-
使用file命令可以查看可执行程序或库文件(.so)的一些信息,例如是32位还是64位的
5-
对于.a的库文件,可以使用nm查看里面的.o成员,也可以 ar x 解压处成员 file
3+
## 如何检查一个库文件或可执行文件是32位的还是64位的
4+
`file _a.out_` 或者 `file _libX.so_`
5+
对于.a的库文件,可以 ar x 解压出成员文件后使用 `file`命令
6+
* 使用nm查看.a里面的.o成员的地址长度也可以判断为32位或64位的
7+
68
**备注**
7-
`file -i 文本文件` 可以显示文件的编码方式
8-
检查文本文件格式,UTF-8格式需要注意是否有BOM标志(EF BB BF)
9-
`cat -v` 可以显示不可打印字符
10-
注意文件的UNIX格式或DOS格式
9+
`file -i _textfilename_` 可以显示文件的编码方式
10+
* 检查文本文件格式,UTF-8格式需要注意是否有BOM标志(EF BB BF)
11+
* `cat -v` 可以显示不可打印字符
12+
* 注意文件的UNIX格式或DOS格式
1113

1214
## size
1315
列出目标文件的各section的大小
@@ -16,51 +18,47 @@
1618
* BSS段:包含未经初始化的全局变量和静态变量。
1719

1820
## 查看可执行文件依赖情况
19-
ldd命令
20-
Linux上ldd命令是一个 bash 的脚本。
21-
Linux下执行ldd,设置LD_TRACE_LOADED_OBJECTS,而动态载入器检查该环境变量,
22-
若设置了则不执行这个程序而是输出这个可执行程序所依赖的动态链接库。下面的命令都可以显示依赖的动态库
21+
Linux上`ldd`命令是一个 bash 的脚本,执行ldd,设置环境变量`LD_TRACE_LOADED_OBJECTS`,而动态载入器检查该环境变量,
22+
若设置了则不执行这个程序而是输出这个可执行程序所依赖的动态链接库。
23+
下面的命令都可以显示依赖的动态库:
2324
* `ldd /bin/grep`
2425
* `LD_TRACE_LOADED_OBJECTS=1 /bin/grep`
2526
* `LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux.so.2 /bin/grep`
2627

2728
## ldd注意事项
2829
如果让别的装载器来取代系统默认的动态链接库(ld-linux.so)的话,
29-
那么就可以让 ldd来载入并运行程序了——使用不同的载装器并且不处理LD_TRACE_LOADED_OBJECTS 环境变量,
30-
而是直接运行程序。例如 uClibc C库。修改(ldso/ldso/ldso.c不处理LD_TRACE_LOADED_OBJECTS)并编译它后,
31-
产生C库与ld-uClibc.so.0。编写程序并使用命令编译:
32-
```shell
33-
$ L=/home/you/app/uclibc
30+
那么就可以让 ldd来载入并运行程序了——使用不处理`LD_TRACE_LOADED_OBJECTS`的载装器
31+
(例如 uClibc C库(修改`ldso/ldso/ldso.c`不处理`LD_TRACE_LOADED_OBJECTS`)并编译产生C库与ld-uClibc.so.0)
32+
编写程序并使用命令编译:
33+
```bash
34+
$ L=/path2uclibc
3435
$ gcc -Wl,--dynamic-linker,$L/lib/ld-uClibc.so.0 \
3536
-Wl,-rpath-link,$L/lib \
3637
-nostdlib \
37-
myapp.c -o myapp \
38+
testapp.c -o testapp \
3839
$L/usr/lib/crt*.o \
3940
-L$L/usr/lib/ \
4041
-lc
4142
```
42-
* -Wl,–dynamic-linker,$L/lib/ld-uClibc.so.0 — 指定一个新的装载器。
43-
* -Wl,-rpath-link,$L/lib — 指定一个首要的动态装载器所在的目录,这个目录用于查找动态库。
44-
* -nostdlib — 不使用系统标准库。
45-
* myapp.c -o myapp — 编译myapp.c 成可执行文件 myapp,
46-
* $L/usr/lib/crt*.o — 静态链接runtime 代码
47-
* -L$L/usr/lib/ — libc 的目录(静态链接)
43+
* -Wl,–dynamic-linker,$L/lib/ld-uClibc.so.0 指定一个新的装载器。
44+
* -Wl,-rpath-link,$L/lib : 指定一个首要的动态装载器所在的目录,这个目录用于查找动态库。
45+
* -nostdlib : 不使用系统标准库。
46+
* $L/usr/lib/crt*.o : 静态链接runtime 代码
47+
* -L$L/usr/lib/ : libc 的目录(静态链接)
4848
* -lc — C 库
4949

50-
这样若`LD_TRACE_LOADED_OBJECTS=1 /bin/grep` 实际上是以执行的用户的权限执行了这个程序(而不是像设想那样列出其以来的动态库)。
51-
ldd脚本实际上是执行了`LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux.so.2 /bin/grep`
52-
`LD_TRACE_LOADED_OBJECTS=1 /lib64/ld-linux.so.2 /bin/grep` (取决于可执行文件是32位还是64位的)
50+
这样若`LD_TRACE_LOADED_OBJECTS=1 /bin/grep` 实际上是以执行的用户的权限执行了这个程序(而不是像设想那样列出其依赖的动态库)。
5351

54-
.interp ELF section为程序的动态加载器。
55-
`objdump –section=.interp –s ./myapp` 查看.interp段的内容
56-
或者
57-
`readelf –l ./myapp`
52+
ELF文件中`.interp`段为程序的动态加载器:
53+
* 查看.interp段的内容
54+
* `objdump –section=.interp –s ./testapp`
55+
* `readelf –l ./testapp`
5856

5957
静态编译的可执行程序都可以作为动态加载器
60-
```shell
61-
gcc -static myapp.c -o loader
62-
gcc -Wl,--dynamic-linker,./loader myapp.c -o myapp
58+
```bash
59+
gcc -static testapp.c -o loader
60+
gcc -Wl,--dynamic-linker,./loader testapp.c -o testapp
6361
```
64-
**备注**:在BSD 系统上的ldd 是一个C 程序
62+
**备注**:在BSD 系统上的ldd 是一个ELF程序
6563

6664

0 commit comments

Comments
 (0)