C ++ - 从调试器

时间:2016-06-29 06:36:44

标签: c++ llvm lldb

使用llvm和lldb处理OSX,我有以下代码:

#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()时,我得到:

  

错误:无法查找符号:__ ZN1A1fEv

但是,

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

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

谢谢!

2 个答案:

答案 0 :(得分:2)

虽然在某些情况下将定义移出线可能会有所帮助,但在所有情况下都无济于事,例如:如果它不是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 documentation

  

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

这意味着即使没有使用,也可以保证在所有情况下都能发出该功能。

(作为进一步的补充,我还没有证实这实际上可以用于LTO优化 - 它可能应该,但我认为这是一个通常不会想到的角落情况,我直到现在才这样做我在LTO工作:)

答案 1 :(得分:1)

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;
}

在Linux上使用gcc 4.8.4,$ g++ t.cc$ g++ -g t.cc对我有用。它也可以与您的工具链一起使用。

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

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

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

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