Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/apache/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在运行时在gdb中添加函数 我尝试调试GDB中的一些基于STL的C++代码。 代码有如下内容 int myfunc() { std::map<int,int> m; ... }_C++_Gdb - Fatal编程技术网

在运行时在gdb中添加函数 我尝试调试GDB中的一些基于STL的C++代码。 代码有如下内容 int myfunc() { std::map<int,int> m; ... }

在运行时在gdb中添加函数 我尝试调试GDB中的一些基于STL的C++代码。 代码有如下内容 int myfunc() { std::map<int,int> m; ... },c++,gdb,C++,Gdb,这似乎是处理这个问题的好方法。。。但是我可以将printmap放入一个单独的对象文件(甚至动态库),然后在运行时加载到gdb中,而不是将其编译到二进制文件中吗?因为每次我想查看另一个STL变量时重新编译二进制文件并不有趣。。编译和加载用于打印例程的单个.o文件可能是可以接受的 更新: 根据尼古拉的建议,我正在看dlopen/dlsym 所以我还没开始工作,但感觉我越来越近了 在printit.cpp中 #include <stdio.h> extern "C" void prin

这似乎是处理这个问题的好方法。。。但是我可以将printmap放入一个单独的对象文件(甚至动态库),然后在运行时加载到gdb中,而不是将其编译到二进制文件中吗?因为每次我想查看另一个STL变量时重新编译二进制文件并不有趣。。编译和加载用于打印例程的单个.o文件可能是可以接受的


更新:

根据尼古拉的建议,我正在看dlopen/dlsym

所以我还没开始工作,但感觉我越来越近了

在printit.cpp中

#include <stdio.h>

extern "C" void printit()
{
  printf("OMG Fuzzies");
}
启动我的测试应用程序并加载。因此,请使用dlopen(2=RTLD_NOW),然后尝试使用dlsym获取调试函数的符号

(gdb) break main
(gdb) run
(gdb) print (void*) dlopen("printit.so", 2 )
$1 = (void *) 0x100270
(gdb) print (void*) dlsym( 0x100270, "_printit" )
$2 = (void *) 0x0
如此接近,但出于某种原因,我无法得到那个符号。。。)如果我把钥匙放进去,我甚至都拿不到 dlopen/dlsym调用在我的可执行文件中)我猜我要么编译错误的库,要么使用不正确的dlsym

如果我能得到这个符号,我假设我可以使用类似

void printmap( std::map<int,int> m )
{
   for( std::map<int,int>::iterator it = ... )
   {
      printf("%d : %d", it->first, it->second );
   }
}
(gdb) print (( void(*)() )(0x....))()
我在OSX10.4上编译这篇文章,这可能会引起我的一些担忧。所以不幸的是。。。任何指点都将不胜感激



找到了如何让这些工作正常进行的方法。已在下面作为解决方案发布。

据我所知,您所要求的不是直接可能的。不过,还有一个很接近的替代方案(谁说的关于一个更高层次的间接性?:)

使用所有打印机例程构建一个单独的动态库,然后向程序中添加延迟加载打印包装器。我的意思是,大致如下:

/// this is in your program, lazy print wrapper
void print_map( const std::map<int,int>& m ) // NOTE THE CONST REFERENCE
{
    static bool loaded = false;
    static void* print_lib = 0;
    static void (*print_func_ptr)( const std::map<int,int>& ) = 0;

    if ( !loaded )
    {
        // dlopen dynamic lib, check for errors, assign to print_lib
        // dlsym the library function by name, assign to print_func_ptr
        loaded = true;
    }

    print_func_ptr( m );
}
///这在您的程序中,惰性打印包装器
void print_map(const std::map&m)//注意const引用
{
静态布尔加载=假;
静态void*print_lib=0;
静态无效(*打印功能)(常量标准::映射-)=0;
如果(!已加载)
{
//打开动态库,检查错误,分配给打印库
//dlsym按名称将库函数指定给print_func_ptr
加载=真;
}
打印功能(m);
}
然后您可以在gdb会话中调用
print\u map
,库将自动加载。 请注意,上面的代码通过常量引用接受映射。你在问题中使用的函数会复制它的参数


另外,请看一些使gdb为STL容器产生更好输出的方法。

我建议看一下这里:


有两种不同的方式显示STL容器(腿部工作已经为您完成)。任何选项都要求您在配置gdb后重新启动它,但最好以后再使用。

因此,我的解决方案是在运行时使用
dlopen
加载包含调试例程的共享对象。事实证明,当所有编译标志都正确时,它比我想象的还要简单

在OS X上,这意味着您可以像这样编译应用程序和调试对象:

all : application.x debug_helper.so

application.x : application.cpp
    g++ -g application.cpp -o application.x -fPIC

debug_helper.so : debug_helper.o
    g++ -dynamiclib -o debug_helper.so debug_helper.o

debug_helper.o : debug_helper.cpp
    g++ -Wall -g -fPIC -c debug_helper.cpp
#include <map>

int main()
{
  std::map<int,int> m;
  m[1]=2;
  m[2]=5;
  m[3]=10;
  m[4]=17;
}
应用程序上的
-fPIC
-dynamiclib
一样重要(而不是尝试linux
-shared
标志)

示例
debug\u helper.cpp
可能如下所示

#include <map>
#include <stdio.h>

extern "C" 
void printMap( const std::map<int,int> &m )
{
  printf("Map of size %d\n", int(m.size()) );
  for( std::map<int,int>::const_iterator it = m.begin(); it!=m.end(); ++it )
  {
    printf("%d : %d \n", it->first, it->second );
  }
  fflush(stdout);
}
GDB是智能的,为我们捕获所有新符号,因此我们不需要使用
dlsym
等。 我们可以直接调用函数

(gdb) call printMap(m)
Map of size 0
(gdb) n
(gdb) n
(gdb) n
9     m[4]=17;
(gdb) call printMap(m)
Map of size 3
1 : 2 
2 : 5 
3 : 10 
让我们向printMap添加更多信息。 首先,卸载库

(gdb) print (int) dlclose($1)
$2 = 0
编辑源以添加条目的总和。重新编译然后加载 将新库返回到gdb(无需重新启动可执行文件或gdb)

使用修改后的函数

(gdb) call printMap(m)
Map of size 3
1 : 2 
2 : 5 
3 : 10 
SUM = 17

我想这可以满足我的所有需要。

是的,我并不在乎调用是否复制了参数。但这个解决方案对我来说仍然不切实际,因为如果我想查看另一个STL类,我需要重新编译二进制文件并重新启动gdb。但是,使用dlopen可能会发现一些问题。我会进一步调查。哦,你现在想要一个解决方案,甚至不离开gdb控制台?现在的孩子们……:)请注意,如果
dlopen
结果是空指针,则提供路径作为
/debug\u助手。因此可能需要
(从
dlopen
手册页:如果文件名包含斜杠(“/”),则将其解释为(相对或绝对)路径名。否则,[…])@user202729这是一个很好的观点,我将更改路径以使用“/”。
(gdb) print (void*) dlopen("./debug_helper.so",2)
Reading symbols for shared libraries . done
$1 = (void *) 0x100270
(gdb) n
6     m[1]=2;
(gdb) call printMap(m)
Map of size 0
(gdb) n
(gdb) n
(gdb) n
9     m[4]=17;
(gdb) call printMap(m)
Map of size 3
1 : 2 
2 : 5 
3 : 10 
(gdb) print (int) dlclose($1)
$2 = 0
(gdb) print (void*) dlopen("./debug_helper.so",2)
Reading symbols for shared libraries . done
$3 = (void *) 0x100270
(gdb) call printMap(m)
Map of size 3
1 : 2 
2 : 5 
3 : 10 
SUM = 17