Blog

需要转储核心文件的三个场景

Content #

  1. 程序在运行很长时间后才出错,无法用调试器重现错误。
  2. 因随机的环境事件导致的段错误。
  3. 普通用户可以向程序员发送核心文件,帮助程序员调试。

From #

conditional breakpoint and watchpoint

Content #

Sometimes it’s useful to tell the debugger to stop at a break point only if some condition is met, like the when a variable has a particularly interesting value. Conditional Breakpoints is similar to watchpoints work, but with an important distinction.

If you have a suspicion about where a variable is getting a bogus value, a conditional breakpoint is preferable to a watchpoint.

The watchpoint will break whenever that variable changes value. The conditional breakpoint will only break at the suspected problem code, and then, only when the variable takes on the bogus value.

...

查看动态数组的内容

Content #

GDB调试的程序使用了动态数组:

x = (int*)malloc(25*sizeof(int));

请问在GDB中该如何查看该数组的内容?

  1. 使用artificial array
p *x@25
  1. 使用强制类型转换
p (int [25]) *x

From #

在变量i>4时得到通知

Content #

GDB中调试下面的程序:

#include <stdio.h>
int i = 0;
int main(void) {
    i = 3;
    printf("i is %d.\n", i);
    i = 5;
    printf("id is %d.\n", i);
    return 0;
}

我们想在i>4时得到通知,请问该如何操作?

先在main的入口放一个断点,以便让i在使用域中,然后设置监视点。 (gdb) break main (gdb) run (gdb) watch i > 4

From #

RAII(Resource Acquisition Is Initialization)

Content #

RAII(Resource Acquisition Is Initialization,资源获取就是初始化),是 C++ 中的一个利用了面向对象的技术。这个设计模式叫“代理模式”。我们可以把一些控制资源分配和释放的逻辑交给这些代理类,然后,只需要关注业务逻辑代码了。而且,在我们的业务逻辑代码中,减少了这些和业务逻辑不相关的程序控制的代码。

mutex m;
void foo() {
    m.lock();
    Func();
    if ( ! everythingOk() ) return;
    ...
    ...
    m.unlock();
}

可以看到,上面这段代码是有问题的,原因是:那个 if 语句返回时没有把锁给 unlock 掉,这会导致锁没有被释放。如果我们要把代码写对,需要在 return 前 unlock 一下。

mutex m;
void foo() {
    m.lock();
    Func();
    if ( ! everythingOk() ) {
        m.unlock();
        return;
    }
    ...
    m.unlock();
}

但是,在所有的函数退出的地方都要加上 m.unlock(); 语句,这会让我们很难维护代码。于是可以使用面向对象的编程模式,我们先设计一个代理类。

class lock_guard {
  private:
    mutex &_m;
  public:
    lock_guard(mutex &m):_m(m) { _m.lock(); }
    ~lock_guard() { _m.unlock(); }
};

然后,我们的代码就可以这样写了:

...

普通断点与条件断点的相互转换

Content #

GDB中对普通断点设置条件可以将其转换成条件断点,为断点3添加条件i==3,该如何操作?

condition 3 i == 3

GDB中删除条件断点3的条件,使之重新成为普通断点,该如何操作?

condition 3

From #

条件断点中使用库函数

Content #

GDB的条件断点中可以使用链接到代码中的库函数,但是,大多数库函数的动态库使用时都不会带有调试符号表,因此,在条件断点中使用库函数会有一个限制,请问是什么?

在条件断点中使用的库函数的返回值会被认为是int。

下面的GDB条件断点设置使用了库函数strlen,它能正确使用的前提条件是什么?

break 44 if strlen(mystring) == 0

库函数被链接到程序中。

From #

until可以退出while循环却不能退出for循环

Content #

用GDB调试下面的两个循环,为什么until命令可以退出while循环,却不能退出 for循环?

int i = 9999;
while (i--) {
  ...
}

int i;
for (i = 0; i < 10; i++) {
  ...
}

From #

In fact, what until really does is execute until it reaches a machine instruction that has a higher memory address than the current one, rather than until it reaches a larger line number in the source code.

GCC编译for循环时,会把循环条件放在循环体的底部,因此,for循环体中的下一条语句是循环条件,从源角度来看,在for循环中使用until后又从新回到了 for语句上。