从调试器中调用未使用的函数

C++ - Calling unused function from debugger

本文关键字:函数 未使用 调用 调试器      更新时间:2023-10-16

在OSX上使用llvm和lldb,我有以下代码:

#include <stdio.h>
class A{
public:
    void f() __attribute__((noinline))
    {
        printf("f()n");
    }
    void g() __attribute__((noinline))
    {
        printf("g()n");
    }
};
int main()
{
    A a;
    a.g();
    return 0;
}

当打破main(),并试图调用p a.f()从调试器我得到:

错误:cannot lookup symbols: __ZN1A1fEv

调用p g.f()效果很好。

我知道f()可能会被优化掉,但是有没有办法禁用这种优化,所以我可以在调试器中使用它?

谢谢!

虽然将定义移出行可能在某些情况下有帮助,但它不会在所有情况下都有帮助,例如,如果它不是odr c++成员函数,而只是一个静态函数,或者如果您的整个程序是LTO优化的,并且该函数没有在本地翻译单元之外被引用。

在这些情况下(可能也是这种情况),您应该将函数标记为__attribute__((used)),以告诉编译器该函数被使用,并确保在结果对象文件中为它生成代码-这也意味着将生成调试信息。

你的最终代码将看起来像这样:

#include <stdio.h>
class A {
public:
  void f() __attribute__((noinline, used))
  {
    printf("f()n");
  }
  void g() __attribute__((noinline))
  {
    printf("g()n");
  }
};
int main()
{
  A a;
  a.g();
  return 0;
}

这是设计__attribute__((used))的原因之一。来自gcc文档:

这个附加到函数的属性意味着必须为该函数发出代码,即使该函数似乎没有被引用。例如,当函数仅在内联汇编中被引用时,这很有用。当应用于c++类模板的成员函数时,该属性还意味着,如果类本身被实例化,则该函数也被实例化。

这意味着即使不使用该函数,也保证在所有情况下都会发出该函数。

(作为进一步的补充,我还没有验证这实际上会为LTO优化工作-它可能应该,但我打赌这是一个不经常想到的角落案例,我直到现在才想到,我在LTO工作:)

f的定义移出类:

#include <stdio.h>
class A {
public:
    void f();
    void g() __attribute__((noinline))
    {
        printf("g()n");
    }
};
void A::f()
{
    printf("f()n");
}
int main()
{
    A a;
    a.g();
    return 0;
}

这已经为我工作与$ g++ t.cc$ g++ -g t.cc在Linux上与gcc 4.8.4。它可能也适用于你的工具链。

$ g++ t.cc
$ nm a.out | grep _ZN1A
000000000040052e T _ZN1A1fEv
0000000000400562 W _ZN1A1gEv

作为一种替代方法,正如在echristo的回答中所描述的,将used添加到f的属性中,并将其保留在类中。这也适用于$ g++ .cc and $ g++ -g .cc ':

$ g++ -g t.cc
0000000000400548 W _ZN1A1fEv
0000000000400560 W _ZN1A1gEv

添加used也适用于g++ -O2 -g t.cc