gdb调试某个程序?
gdb xxx。或者gdb,进入gdb之后,file xxx。首先在当前目录找xxx,如果找不到就在PATH环境变量所指定的所有目录里面依次寻找。不仅可以调试自己开发的程序,而且可以调试github上所有源码编译的程序。
gdb设置调试参数?
首先需要进入gdb,然后set args xxx。调试的时候可能之前在命令行不会报错的现在会报错,比如utf8,在shell命令行输入的时候utf8被处理成UTF-8,在gdb里面可不会处理,直接报错不认识。如果想查看当前已经设置的参数,使用show args。
gdb查看当前在哪个源文件里?
info source
gdb切换源文件?
不能自己切换,但是可以查看所有源文件,info sources,这个挺nb。
可以使用b命令在指定源文件下断点。如`b /home/bibo/codes/libiconv-1.17/lib/iconv.c:1`表示在/home/bibo/codes/libiconv-1.17/lib/iconv.c的第一行下断点。
找到某个变量的定义?
where x
1024 cd = iconv_open(tocode,fromcode);
1024 cd = iconv_open(tocode,fromcode);
(gdb)
Breakpoint 1, libiconv_open (tocode=tocode@entry=0x7fffffffe330 "UTF-8",
fromcode=fromcode@entry=0x7fffffffe329 "GBK") at ./iconv.c:235
235 {
(gdb) p tocode
$5 = 0x7fffffffe330 "UTF-8"
(gdb) p fromcode
$6 = 0x7fffffffe329 "GBK"
if (c >= 'a' && c <= 'z')
c -= 'a'-'A';
这样小写字符转为大写也是够nb的。
想知道iconv是怎样将gbk转为utf8的,正在使用gbd调试,但还没结束。
iconv_canonicalize
./src/iconv.c:1109 FILE* infile = fopen(infilename,"r");
1120 status |= convert(cd,fileno(infile),infilename);
gcc -std=gnu11 -c -I. -I. -I.. -I../include -I./../include -I../srclib -I./../srclib -I../lib -g -O2 -DINSTALLDIR=\"/usr/local/bin\" -DLOCALEDIR=\"/usr/local/share/locale\" ./iconv.c
gcc -std=gnu11 -DHAVE_CONFIG_H -DEXEEXT=\"\" -I. -I.. -I../lib -DDEPENDS_ON_LIBICONV=1 -DDEPENDS_ON_LIBINTL=1 -fvisibility=hidden -Wno-cast-qual -Wno-conversion -Wno-float-equal -Wno-sign-compare -Wno-undef -Wno-unused-function -Wno-unused-parameter -Wno-pedantic -Wno-sign-conversion -Wno-type-limits -Wno-unsuffixed-float-constants -g -O2 -c -o libicrt_a-allocator.o `test -f 'allocator.c' || echo './'`allocator.c
all : lib/localcharset.h force
cd lib && $(MAKE) all
cd srclib && $(MAKE) all
cd src && $(MAKE) all
cd po && $(MAKE) all
cd man && $(MAKE) all
在配置时设置gcc环境变量?
./configure CFLAGS="-g -O0"
我所需要具备的,不是掌握一个命令的所有用法,也不是掌握所有的命令的功能,而是去完成一个需求时,所需要具备的一整套能力。
-f gbk -t UTF-8 1.txt
1109 FILE* infile = fopen(infilename,"r");
Missing separate debuginfos, use: debuginfo-install glibc-2.17-317.el7.x86_64
(gdb) p infilename
$1 = 0x7fffffffe30c "iconv"
gdb设置满足某条件时停下来?
break mian if xxx
gdb找到函数定义?
info function xxx
./src/iconv.c
697 inbufsize = safe_read(infile,inbuf+4096,4096);
717 size_t res = iconv(cd,(ICONV_CONST char**)&inptr,&insize,&outptr,&outsize);
函数传参传地址时,就好像传递一个碗,人家把我要的东西放在这个碗里,然后我就能拿到。
传地址的地址,就像传递碗外面的一个碗,人家把我要的碗放在这个碗里,我再通过我要的碗找里面的东西。
./lib/iconv.c
270 return cd->lfuncs.loop_convert(icd,
271 (const char* *)inbuf,inbytesleft,
272 outbuf,outbytesleft);
./lib/loop_unicode.h
268 static size_t unicode_loop_convert (iconv_t icd,
269 const char* * inbuf, size_t *inbytesleft,
270 char* * outbuf, size_t *outbytesleft)
283 incount = cd->ifuncs.xxx_mbtowc(cd,&wc,inptr,inleft);
./lib/ces_gbk.h
24 static int
25 ces_gbk_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
36 return gbk_mbtowc(conv,pwc,s,2);
gbk "武汉"
206 228 186 186
utf8“武汉”
230 173 166 230 177 137
wchar_t"武"
27494
./lib/gbk.h
62 static int
63 gbk_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
86 ret = gb2312_mbtowc(conv,pwc,buf,2);
./lib/gb2312.h
1080 static int
1081 gb2312_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
1082 {
1095 wc = gb2312_2uni_page30[i-1410];
}
/lib/loop_unicode.h
283 incount = cd->ifuncs.xxx_mbtowc(cd,&wc,inptr,inleft);
361 outcount = cd->ofuncs.xxx_wctomb(cd,outptr,wc,outleft);
执行完这一句,就能看见“武”了。输入输出并没有放在一起,一次只处理一个字符。
/lib/ces_gbk.h
36 return gbk_mbtowc(conv,pwc,s,2);
72 static int
73 utf8_wctomb (conv_t conv, unsigned char *r, ucs4_t wc, size_t n) /* n == 0 is acceptable */
74 {
75 int count;
76 if (wc < 0x80)
77 count = 1;
78 else if (wc < 0x800)
79 count = 2;
80 else if (wc < 0x10000) {
(gdb)
81 if (wc < 0xd800 || wc >= 0xe000)
82 count = 3;
83 else
84 return RET_ILUNI;
85 } else if (wc < 0x110000)
86 count = 4;
87 else
88 return RET_ILUNI;
89 if (n < count)
90 return RET_TOOSMALL;
(gdb)
91 switch (count) { /* note: code falls through cases! */
92 case 4: r[3] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x10000;
93 case 3: r[2] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x800;
94 case 2: r[1] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0xc0;
95 case 1: r[0] = wc;
96 }
97 return count;
98 }
iconv将gbk转为utf8,在最底层是一个字符一个字符转,现将gbk的汉字转为宽字符的汉字,再讲宽字符的汉字填入utf8要求的格式。
所谓gbk,是中国制定的字符集标准,一个汉字对应一个gbk编码。
所谓宽字符,实质是unicode,是世界定制的字符集标准,一个汉字对应一个unicode编码。
所谓utf8,并不是一个字符集,只是一个编码方案,将unicode转为utf8所需要的格式,就是utf8编码。
0800~ FFFF 12~16 1110 XXXX 10 XX XXXX 10 XX XXXX 3
gbk "武汉"
206 228 186 186
utf8“武汉”
230 173 166 230 177 137
1110 0110 10 101101 10 100110
wchar_t"武"
27494
0110 101101 100110
iconv在将gbk转为unicode的时候,是查表完成的,gb2312.h里的数组信息,就是它查询使用的表,和预想一致。只是它查询的表特别简单,只是几个数组,就能保存这么多的汉字。2000行代码,一行8个汉字,就有16000个汉字,已经足够使用了。
unicode转utf8,使用算法就好了。
./lib/gb2312.h
1080 static int
1081 gb2312_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, size_t n)
1082 {
1095 wc = gb2312_2uni_page30[i-1410];
}
这里的s是哪来的,s的值是“Nd”?汉字武的值是206 228 186 186。
/lib/gbk.h:85
85 buf[0] = c-0x80; buf[1] = c2-0x80;
78 100
这里来的,对gbk编码的两个字节分别减去了0x80。至于为什么减去0x80,现在不研究,以后再说。
为什么从cd->lfuncs.loop_convert直接跳到unicode_loop_convert了,函数名字并不一样?
./lib/iconv.c
270 return cd->lfuncs.loop_convert(icd,
271 (const char* *)inbuf,inbytesleft,
272 outbuf,outbytesleft);
/src/iconv.c
850 iconv_t cd;
851 struct iconv_fallbacks fallbacks;
852 struct iconv_hooks hooks;
那就首先要知道iconv_t, iconv_fallbacks, iconv_hooks的定义。
(gdb) whatis iconv_t
type = void *
1024 cd = iconv_open(tocode,fromcode);
(gdb) p fallbacks
$48 = {mb_to_uc_fallback = 0x0, uc_to_mb_fallback = 0x0,
mb_to_wc_fallback = 0x0, wc_to_mb_fallback = 0x0, data = 0x0}
说明iconv_fallbacks是一个数组,里面装有4个函数指针
1094 iconvctl(cd, ICONV_SET_FALLBACKS, &fallbacks);
(gdb) p hooks
$51 = {uc_hook = 0x4016bc
1100 iconvctl(cd, ICONV_SET_HOOKS, &hooks);
(gdb) p cd
$53 = (conv_t) 0x609010
(gdb) p *cd
$54 =
{
lfuncs =
{loop_convert = 0x7ffff7b08507
loop_reset = 0x7ffff7b089d3
iindex = 94,
ifuncs = {xxx_mbtowc = 0x7ffff7afdc08
istate = 0,
oindex = 1,
ofuncs = {xxx_wctomb = 0x7ffff7aed67e
oflags = 7,
ostate = 0,
transliterate = 0,
discard_ilseq = 0,
fallbacks = {
mb_to_uc_fallback = 0x0,
uc_to_mb_fallback = 0x0,
mb_to_wc_fallback = 0x0,
wc_to_mb_fallback = 0x0,
data = 0x0},
hooks = {uc_hook = 0x4016bc
}
cd->lfuncs.loop_convert
到这里已经一目了然了。cd是一个指针,lfuncs是一个结构体,loop_convert是一个函数指针,指向将要调用的unicode_loop_convert函数。
iconv.c
1024 cd = iconv_open(tocode,fromcode);
iconv_open是怎样通过tocode,fromcode字符串来找到相应的函数指针的?
225 from_index = ap->encoding_index;
(gdb) p *ap
$67 = {name = 1879, encoding_index = 94}
34 cd->ifuncs = all_encodings[from_index].ifuncs;
(gdb) p from_wchar
$70 = 0
(gdb) p all_encodings
$71 = {{ifuncs = {xxx_mbtowc = 0x7ffff7aed3c5
xxx_flushwc = 0x0}, ofuncs = {xxx_wctomb = 0x7ffff7aed403
xxx_reset = 0x0}, oflags = 0}, {ifuncs = {
xxx_mbtowc = 0x7ffff7aed435
xxx_wctomb = 0x7ffff7aed67e
ifuncs = {xxx_mbtowc = 0x7ffff7aed799
ofuncs = {xxx_wctomb = 0x7ffff7aed8a8
...
all_encodings是一个数组,里面记录了一系列输入输出函数指针对的地址。
在一个数组里面保存了所有的转换需要用到的函数,
ated in /home/bibo/codes/libiconv-1.17/lib/iconv_open1.h
83 ap = aliases_lookup(buf,bp-buf);
前面只是将小写转大写,这里才是真正去通过utf-8找索引。
(gdb) s
aliases_lookup (str=0x7fffffffdd90 "UTF-8", len=5) at lib/aliases.gperf:276
struct alias { int name; unsigned int encoding_index; };
23 UTF-8, ei_utf8
324 GBK, ei_ces_gbk
结构体alias记录了字符串到函数名的映射。
实际上是在lib/aliases.h:1760,gdb调试器没有跟进来。
register unsigned int key = aliases_hash (str, len);
utf8
$98 = {name = 1883, encoding_index = 1}
gbk
$101 = {name = 1879, encoding_index = 94}
首先通过字符串与字符串长度计算hash,然后通过hash在数组中直接找到确定的alias结构体,里面包含int类型的编码名字和编码索引。gbk获取的索引就给from_index,接着给cd->iindex,通过from_index将all_encodings里面的ifuncs给cd->ifuncs。
61 cd->lfuncs.loop_convert = unicode_loop_convert;
解码的时候会在unicode_loop_convert里面去真正调用ifuncs。