如何撤销strip - 即将符号添加回去到被strip的二进制文件中。

23
我有一个剥离了符号表的二进制文件和符号文件。是否可以将符号添加回二进制文件并创建未剥离的二进制文件。
我的用例是在valgrind中使用此二进制文件。

3
我建议重新编译,想不到其他办法 :) - mata
4个回答

17
对于不支持将调试信息单独存储的工具,您可以将调试部分粘结回原始二进制文件。例如,您可以执行以下操作:
  • First build a small program that efficiently extracts an arbitrary chunk from a file

    (note that dd will not do this efficiently as we'd have to use bs=1 to support an arbitrary offset and length, and objcopy -O binary does not copy sections that are not ALLOC, LOAD)

    cat <<EOF | gcc -xc -o ./mydd -
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <macros.h>
    
    char buf[1024*1024];
    
    int main(int argc, char** argv) {
      char    *fin, *fout;
      int     fdin, fdout;
      off_t   off;
      size_t  len;
      ssize_t rd;
      int     status;
    
      if (argc != 5) {
        fprintf(stderr, "Usage: %s fin skip count fout\n", argv[0]);
        return 1;
      }
    
      fin   = argv[1];
      off   = strtoul(argv[2], NULL, 0);
      len   = strtoul(argv[3], NULL, 0);
      fout  = argv[4];
      fdin  = -1;
      fdout = -1;
    
      if ((fdin  = open(fin,  O_RDONLY)) < 0) {
        status = errno;
        perror(fin);
      } else if ((fdout = open(fout, O_WRONLY|O_TRUNC|O_CREAT, 0660)) < 0) {
        status = errno;
        perror(fout);
      } else if (lseek(fdin, off, SEEK_SET) == (off_t)-1) {
        status = errno;
        perror("Seeking input");
      } else {
        while (len > 0 && (rd = read(fdin, buf, min(len, sizeof(buf)))) > 0) {
          if (write(fdout, buf, rd) != rd) {
            /*don't bother with partial writes or EINTR/EAGAIN*/
            status = errno;
            perror(fin);
            break;
          }
          len -= rd;
        }
        if (rd < 0) {
          status = errno;
          perror(fin);
        }
      }
      if (fdin >= 0)  close(fdin);
      if (fdout >= 0) close(fdout);
      return status;
    }
    EOF
    
  • Finally, extract the .debug sections and glue them to the stripped binary.

    objcopy `
        objdump -h program.dbg  |
        awk '$2~/^\.debug/' |
        while read idx name size vma lma off algn ; do
            echo "$name" >&2
            echo " --add-section=$name=$name.raw"
            ./mydd program.dbg 0x$off 0x$size $name".raw"
        done
    ` program program_with_dbg
    

dd可以在不将块大小缩小到1的情况下寻址到任意地址。请参阅dd手册中的“skip_bytes”标志。 - Narcolessico
请注意,这不会复制与节相关联的重定位。 - Tavian Barnes

8
< p > elfutils 自带工具 eu-unstrip 可用于将符号文件与可执行文件合并。合并后的结果可替代剥离版本。


对于像我一样犯了同样错误的人,手册并不是最好的选择,而且做出了一个有趣的决定。"如果没有给出-o选项,则第一种形式将结果放在DEBUG-FILE中。" 如果您只提供从.so文件剥离后的文件,然后是从剥离到.so.debug文件,最终结果将放置在.so.debug文件中。我认为可以肯定地说,几乎任何人都希望合并的符号回到从.so文件中剥离的文件中。或者也许他们对“STRIPPED-FILE”的使用在“剥离自”或“剥离到”方面存在歧义? - JoeManiaci
1
参考:eu-unstrip binary binary.dbg:现在,binary.dbg 包含二进制文件和调试符号。 - Étienne

5

不过,你不能从剥离的二进制文件创建未剥离的二进制文件(至少不容易)。但是你不应该需要这样做,因为这个答案已经正确地说明了。 - Employed Russian
很抱歉,我不清楚如何使用这个带有valgrind的调试文件。如果有任何指导,将不胜感激。 - cached
“answer here” 中提供的指示似乎非常清晰。您需要构建单独的 debuginfo,然后 Valgrind 和 GDB 将自动加载它们。 - Employed Russian
谢谢 - 我会试一下的。 - cached

0
虽然预计Ghidra将支持.debug文件,但合并比阅读两个文件要容易得多。 8-)
根据https://dev59.com/I2Qo5IYBdhLWcg3wivwi#17599967中的代码,可以避免编译自己的复制例程,并使用常规的dd命令(代价是一些减速-复制1个字节不是最快的方法)。
#!/usr/bin/bash
BIN=program
DBG=program.dbg
OUT=program.full

objcopy $(
    objdump -h ${DBG}   |
    awk '$2~/^\.debug/' |
    while read idx name size vma lma off algn ; do
        ARGS=$(printf "skip=%llu count=%llu" 0x$off 0x$size)
        echo "$name ${ARGS}" >&2
        echo " --add-section=$name=$name.raw"
        dd if=${DBG} of=$name".raw" bs=1 ${ARGS} status=progress >&2
    done
) ${BIN} ${OUT}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接