使用gdb调试iconv

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 <update_line_column>, wc_hook = 0x0, data = 0x2}

1100        iconvctl(cd, ICONV_SET_HOOKS, &hooks);

(gdb) p cd

$53 = (conv_t) 0x609010

(gdb) p *cd

$54 = 

{

    lfuncs = 

        {loop_convert = 0x7ffff7b08507 <unicode_loop_convert>,  

        loop_reset = 0x7ffff7b089d3 <unicode_loop_reset>}, 

    iindex = 94, 

    ifuncs = {xxx_mbtowc = 0x7ffff7afdc08 <ces_gbk_mbtowc>, xxx_flushwc = 0x0}, 

   istate = 0, 

    oindex = 1, 

    ofuncs = {xxx_wctomb = 0x7ffff7aed67e <utf8_wctomb>,  xxx_reset = 0x0}, 

    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 <update_line_column>, wc_hook = 0x0, data = 0x0}

}

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 <ascii_mbtowc>, 

      xxx_flushwc = 0x0}, ofuncs = {xxx_wctomb = 0x7ffff7aed403 <ascii_wctomb>, 

      xxx_reset = 0x0}, oflags = 0}, {ifuncs = {

      xxx_mbtowc = 0x7ffff7aed435 <utf8_mbtowc>, xxx_flushwc = 0x0}, ofuncs = {

      xxx_wctomb = 0x7ffff7aed67e <utf8_wctomb>, xxx_reset = 0x0}, oflags = 7}, {

    ifuncs = {xxx_mbtowc = 0x7ffff7aed799 <ucs2_mbtowc>, xxx_flushwc = 0x0}, 

    ofuncs = {xxx_wctomb = 0x7ffff7aed8a8 <ucs2_wctomb>, xxx_reset = 0x0}, 

...

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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值