kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

修改elf文件标记的源码路径debugedit,find-debuginfo

1
2
yum install rpm-build
sudo apt-get install rpm

/usr/lib/rpm/debugedit 用来改变源码查找路径。

1
2
3
4
5
6
7
8
9
10
11
$ /usr/lib/rpm/debugedit
Usage: debugedit [OPTION...]
  -b, --base-dir=STRING      base build directory of objects
  -d, --dest-dir=STRING      directory to rewrite base-dir into
  -l, --list-file=STRING     file where to put list of source and header file
	                     names
  -i, --build-id             recompute build ID note and print ID on stdout

Help options:
  -?, --help                 Show this help message
  --usage                    Display brief usage message

base-dir 长度要大等于 dest-dir
-i 输出build-id
-l 输出源编译文件位置,便于有需要的人打包

debugedit 会在.debug_info .debug_abbrev .debug_line .debug_str中将base_dir目录替换为dest_dir目录。
* 需要注意,如果base_dir是路径中除文件名的部分,则.debug_line中的The Directory Table的目录和.debug_info中的DW_AT_comp_dir(指向.debug_str的内容)不会替换。
如:
.debug_line中的Table中有一个目录为/root/Desktop,如果用 -b /root/Desktop则匹配不上这条。
* 因为:debugedit在匹配的时候在base_dir和dest_dir后面加了一个'/‘
其他部分能替换是因为他们存的是文件路径,不是文件夹路径


内核处理debuginfo的时候,只会替换DW_AT_comp_dir。因为DW_AT_name是一个相对地址


可以修改debugedit源码,base_dir、dest_dir后面不再默认添加'/‘,只是单纯的把base_dir替换成dest_dir

http://vault.centos.org/6.7/os/Source/SPackages/rpm-4.8.0-47.el6.src.rpm

http://vault.centos.org/5.11/updates/SRPMS/rpm-4.4.2.3-36.el5_11.src.rpm

删除tool/debugedit.c中的下面代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  if (base_dir != NULL && base_dir[strlen (base_dir)-1] != '/')
    {
      p = malloc (strlen (base_dir) + 2);
      strcpy (p, base_dir);
      strcat (p, "/");
      free (base_dir);
      base_dir = p;
    }
  if (dest_dir != NULL && dest_dir[strlen (dest_dir)-1] != '/')
    {
      p = malloc (strlen (dest_dir) + 2);
      strcpy (p, dest_dir);
      strcat (p, "/");
      free (dest_dir);
      dest_dir = p;
    }

debugedit -l在输出.debug_line的时候会去除base_dir、dest_dir前缀,由于他们不是以/结尾,所以输出的文件会以/开头,类似/net/ipv4/tcp_input.c,下一步按这个目录去copy文件时就copy不到。所以应该把开头的/去掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
diff --git a/tools/debugedit.c b/tools/debugedit.c
index 064ac0a..bda05db 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -588,9 +588,9 @@ edit_dwarf2_line (DSO *dso, uint_32 off, char *comp_dir, int phase)
          if (base_dir == NULL)
            p = s;
          else if (has_prefix (s, base_dir))
-           p = s + strlen (base_dir);
+           { p = s + strlen (base_dir); if (*p == '/') p++; }
          else if (has_prefix (s, dest_dir))
-           p = s + strlen (dest_dir);
+           { p = s + strlen (dest_dir); if (*p == '/') p++; }

          if (p)
            {

debugedit_el6

debugedit_el5


.debug_str段保存着所有全局变量的名字,以0x00作为每一个全局变量名的结束。
在其它段来调用名字时,是以其在.debug_str段的偏移量来实现的
gcc -g /root/Desktop/a.c -o /root/Desktop/a.out
用绝对路径编译,在.debug_str段中就会存下源文件路径,.debug_info的DW_TAG_compile_unit中的DW_AT_name对应.debug_str中的偏移。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ objdump --dwarf=str a.out
....
  0x00000000 474e5520 4320342e 342e3720 32303132 GNU C 4.4.7 2012
  0x00000010 30333133 20285265 64204861 7420342e 0313 (Red Hat 4.
  0x00000020 342e372d 3429006c 6f6e6720 756e7369 4.7-4).long unsi
  0x00000030 676e6564 20696e74 002f726f 6f742f44 gned int./root/D
  0x00000040 65736b74 6f702f61 2e630075 6e736967 esktop/a.c.unsig
  0x00000050 6e656420 63686172 006d6169 6e006c6f ned char.main.lo
  0x00000060 6e672069 6e74002f 726f6f74 2f446573 ng int./root/Des
  0x00000070 6b746f70 0073686f 72742075 6e736967 ktop.short unsig
  0x00000080 6e656420 696e7400 73686f72 7420696e ned int.short in
  0x00000090 7400                                t.


$ objdump --dwarf=info a.out
.....
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
	< c>   DW_AT_producer    : (indirect string, offset: 0x0): GNU C 4.4.7 20120313 (Red Hat 4.4.7-4)
	<10>   DW_AT_language    : 1        (ANSI C)
	<11>   DW_AT_name        : (indirect string, offset: 0x39): /root/Desktop/a.c
	<15>   DW_AT_comp_dir    : (indirect string, offset: 0x67): /root/Desktop
	<19>   DW_AT_low_pc      : 0x4004c4
	<21>   DW_AT_high_pc     : 0x40051c
	<29>   DW_AT_stmt_list   : 0x0

1
$ /usr/lib/rpm/debugedit -b /root/Desktop -d /usr/src /root/Desktop/a.out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ objdump --dwarf=str a.out
...
  0x00000000 474e5520 4320342e 342e3720 32303132 GNU C 4.4.7 2012
  0x00000010 30333133 20285265 64204861 7420342e 0313 (Red Hat 4.
  0x00000020 342e372d 3429006c 6f6e6720 756e7369 4.7-4).long unsi
  0x00000030 676e6564 20696e74 002f7573 722f7372 gned int./usr/sr
  0x00000040 632f612e 63002f61 2e630075 6e736967 c/a.c./a.c.unsig
  0x00000050 6e656420 63686172 006d6169 6e006c6f ned char.main.lo
  0x00000060 6e672069 6e74002f 726f6f74 2f446573 ng int./root/Des
  0x00000070 6b746f70 0073686f 72742075 6e736967 ktop.short unsig
  0x00000080 6e656420 696e7400 73686f72 7420696e ned int.short in
  0x00000090 7400                                t.


$ objdump --dwarf=info a.out

...
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
	< c>   DW_AT_producer    : (indirect string, offset: 0x0): GNU C 4.4.7 20120313 (Red Hat 4.4.7-4)
	<10>   DW_AT_language    : 1        (ANSI C)
	<11>   DW_AT_name        : (indirect string, offset: 0x39): /usr/src/a.c
	<15>   DW_AT_comp_dir    : (indirect string, offset: 0x67): /root/Desktop
	<19>   DW_AT_low_pc      : 0x4004c4
	<21>   DW_AT_high_pc     : 0x40051c
	<29>   DW_AT_stmt_list   : 0x0