• gdbserver调试共享库(终结版)


    转载时请注明出处和作者联系方式
    文章出处:http://www.limodev.cn/blog
    作者联系方式:李先静 <xianjimli at hotmail dot com>

    我 已经写过两篇关于gdbserver调试共享库的BLOG了:第一篇解决了调试共享库的难题,让调试共享库成为可能,但是使用起来很麻烦。第二篇做了点改 进,通过一个脚本文件计算偏移量,使用起来稍微方便一点。几年过去了,gdbserver还是不支持调试共享库,我也受够了,最终决定去修改了gdb的代 码。其实我们要做的就是计算共享库加载符号表的地址,算法很简单:

    共享库加载符号表的地址 = 共享库在内存中的加载地址+代码段的偏移量。

    实现原理如下:
    o 通过gdbserver读/proc/$pid/maps文件,以获取共享库在内存中的加载地址。
    o 通过bfd查询共享库的代码段的偏移量。
    o 计算共享库加载符号表的地址。
    o 调用add-symbol-file加载符号表。

    具体实现如下:

    o gdbserver增加qMaps请求(gdb/gdbserver/server.c)

    void
    handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
    {if (strncmp (own_buf, "qMaps;", 5) == 0)
        {
          handle_q_maps (own_buf);
          return;
        }}

    o gdbserver处理qMaps请求

    handle_q_maps (char *own_buf)
    {
        FILE* fp = NULL;
        char file_name[256] = {0};
     
        snprintf(file_name, sizeof(file_name), "/proc/%ld/maps", signal_pid);
        if((fp = fopen(file_name, "rb")) != NULL)
        {
            char line[512] = {0};
            while(fgets(line, sizeof(line), fp) != NULL)
            {
                putpkt(line);
            }
            putpkt("<end>");
            fclose(fp);
        }

    包的大小有限制(2000),所以我们只传一行过去,最后再发”“表示传输结束。

    o修改gdb/remote.c解析maps文件。

    static Maps* maps_parse(Maps* maps, char* maps_str)
    {
      char* line = maps_str;
      char* next_line = NULL;
      while(line != NULL)
      {
        next_line = strchr(line, '/n');
        if(next_line != NULL)
        {
          *next_line = '/0';
          next_line++;
        }
     
        if(strstr(line, "r-xp") != NULL && strstr(line, ".so") != NULL)
        {
          int unused = 0;
          MapsItem item;
          memset(&item, 0x00, sizeof(item));
     
          sscanf(line, "%08x-%08x r-xp %08x %02x:%02x %d %s",
            &(item.start), &(item.end), &unused, &unused, &unused, &unused, item.file_name);
          maps_add(maps, &item);
    }
        line = next_line;
      }
     
      return maps;
    }

    o修改gdb/remote.c获取代码段的偏移量。

    int remote_get_so_vma(const char* file_name, size_t* vma)
    {
      char **matching = NULL;
      bfd* b = bfd_openr(file_name, NULL);
     
      if(b != NULL && bfd_check_format_matches (b, bfd_object, &matching))
      {
        asection* s = bfd_get_section_by_name(b, ".text");
        if(s != NULL)
        {
          *vma = s->vma;
     
          return 1;
        }
      }
     
      return 0;
    }

    o 修改gdb/symfile.c实现add_shared_symbol_files_command,这个函数在linux下没有实现。

    static void
    add_shared_symbol_files_command (char *args, int from_tty)
    {
    #ifdef ADD_SHARED_SYMBOL_FILES
      ADD_SHARED_SYMBOL_FILES (args, from_tty);
    #else
    /*support sharelib: {*/
      extern void   remote_list_so(void);
      extern int    remote_get_so_nr(void);
      extern int    remote_get_so_vma(const char* file_name, size_t* vma);
      extern int    remote_get_so_text_start_addr(const char* file_name, size_t* addr);
      extern int    remote_get_so_name_text_start_addr(int index, const char** file_name, size_
    t* addr);
     
      if (current_target.to_shortname &&
          (strcmp (current_target.to_shortname, "remote") == 0
           || strcmp (current_target.to_shortname, "extended-remote") == 0))
      {
        size_t addr = 0;
    char cmd[2048] = {0};
    if(args == NULL || args[0] == '/0')
        {
          printf_unfiltered("available so:/n");
          remote_list_so();
          printf_unfiltered("usage: add-shared-symbol-files file/n");
          printf_unfiltered("usage: add-shared-symbol-files all remote_path:local_path/n");
     
          return;
        }
        else if(strncmp(args, "all ", 4) == 0)
        {
          size_t i = 0;
          size_t n = 0;
          int rlen = 0;
          char rpath[260] = {0};
          char lpath[260] = {0};
          char* p = strchr(args, ':');
          const char* file_name = NULL;
          if(p == NULL) return;
     
          *p = '/0';
          strncpy(lpath, p + 1, sizeof(lpath));
    strncpy(rpath, args + 4, sizeof(rpath));
     
          rlen = strlen(rpath);
          n = remote_get_so_nr();
          for(i = 0; i < n; i++)
          {
            remote_get_so_name_text_start_addr(i, &file_name, &addr);
            if(file_name != NULL && strncmp(file_name, rpath, rlen) == 0)
            {
              size_t vma = 0;
              char lfile_name[512] = {0};
     
              snprintf(lfile_name, sizeof(lfile_name),"%s/%s", lpath, file_name+rlen);
              if(remote_get_so_vma(lfile_name, &vma))
              {
                addr += vma;
              }
              snprintf(cmd, sizeof(cmd),"%s/%s %p", lpath, file_name+rlen, (void*)addr);
              add_symbol_file_command(cmd, 0);
            }
          }
        }
        else
        {
          remote_get_so_text_start_addr(args, &addr);
     
          if(addr > 0)
          {
            size_t vma = 0;
            if(remote_get_so_vma(args, &vma))
            {
              addr += vma;
            }
            snprintf(cmd, sizeof(cmd), "%s %p", args, (void*)addr);
            add_symbol_file_command(cmd, from_tty);
          }
          else
          {
            printf_unfiltered("%s is not found./n", args);
          }
        }
        return;
      }
    /*support sharelib: }*/
      error (_("This command is not available in this configuration of GDB."));
    #endif
    }

    使用方法:
    o 加载单个共享库的符号表。add-shared-symbol-files 共享库文件名(本地绝对路径).
    o 加载多个共享库的符号表。add-shared-symbol-files all 远程路径:本地路径

    因为加载符号表时是加载本地文件,所以加载多个文件时,要把远程路径替换成本地路径。

    需要代码的朋友请到这里(三个修改的文件)下载。
    参考:
    gdb编译方法:http://blog.csdn.net/absurd/archive/2006/08/19/1097392.aspx
    用gdbserver调试共享库(改进版): http://blog.csdn.net/absurd/archive/2007/09/20/1793646.aspx

  • 相关阅读:
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons)
    Logical partitioning and virtualization in a heterogeneous architecture
    十条实用的jQuery代码片段
    十条实用的jQuery代码片段
    十条实用的jQuery代码片段
    C#比较dynamic和Dictionary性能
    C#比较dynamic和Dictionary性能
    C#比较dynamic和Dictionary性能
    分别使用 XHR、jQuery 和 Fetch 实现 AJAX
    分别使用 XHR、jQuery 和 Fetch 实现 AJAX
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167507.html
Copyright © 2020-2023  润新知