代码之家  ›  专栏  ›  技术社区  ›  Richard Corden

我可以让gdb跳过函数末尾的throw语句吗?

  •  4
  • Richard Corden  · 技术社区  · 16 年前

    在调试时,我有时会发现“重放”代码的最后几条语句很有用。例如:

    void foo (int & i) {
      i = 0;
      ++i;
      i++;
    }
    

    在通过调试器运行此命令时,可以在函数体的顶部添加断点,然后从函数体内部的任何语句添加断点。 foo 如果键入:“jump file.cc:2”,调试器将返回到 i = 0 . 我很感激这并不总是完美的,但有时它足以找到你正在寻找的bug。

    我目前正在调查一个导致抛出异常的问题。异常正在被调用函数的底部引发,因此类似于:

    void bar ()
    {
      throw int ();
    }
    
    void foo (int & i)
    {
      i = 0;
      ++i;
    
      bar ();
    
      i++;
    }
    
    int main ()
    {
      try
      {
        int i;
        foo (i);
      }
      catch (...)
      {
      }
    }
    

    我想做的是在 throw int () ,然后跳过该语句,完成函数栏-这样我就可以跳回到 i=0 在FO中行。

    我有办法跳过吗 投掷int() 或完成 bar 不执行throw语句?

    问题似乎是在 throw 所以我没有地方放置我想要跳转到的断点。

    更新:

    要突出显示上面我的简单示例中发生的情况:

    This GDB was configured as "i486-slackware-linux"...
    (gdb) break bar
    Breakpoint 1 at 0x804856a: file t.cc, line 3.
    (gdb) run
    Starting program: ..../t 
    
    Breakpoint 1, bar () at t.cc:3
    (gdb) break t.cc:4
    Breakpoint 2 at 0x8048592: file t.cc, line 4.
    (gdb) jump t.cc:4
    Line 4 is not in `bar()'.  Jump anyway? (y or n) y
    Continuing at 0x8048592.
    
    Breakpoint 2, foo (i=@0xb80155eb) at t.cc:6
    

    “bar”的close curly位于“t.cc”的第4行,但是gdb将其视为 .

    5 回复  |  直到 12 年前
        1
  •  5
  •   Justin    16 年前

    是的,你可以。您需要将指令指针设置为所需的值。

      (gdb) set $eip = 0xValue
    
        2
  •  5
  •   Richard Corden    16 年前

    我的拼写错误实际上给了我答案!

    我对“反汇编”的修改不起作用,所以在寻找正确的拼写时,我最终偶然发现了“帮助堆栈”:

    正在检查堆栈。 堆栈由堆栈帧组成。gdb为堆栈帧分配数字 从零开始对最里面的(当前正在执行的)帧进行计数。

    在任何时候,gdb都将一个帧标识为“选定”帧。 变量查找是针对所选帧完成的。 当被调试的程序停止时,gdb选择最里面的帧。 下面的命令可用于按编号或地址选择其他帧。

    命令列表:

    backtrace—打印所有堆栈帧的backtrace

    bt—打印所有堆栈帧的回溯

    down——选择并打印此堆栈调用的堆栈帧

    帧--选择并打印堆栈帧

    返回--使所选堆栈帧返回到其调用方

    选择帧--选择一个堆栈帧而不打印任何内容

    向上--选择并打印调用此帧的堆栈帧

    这个 返回 上面列表中的命令执行我在本例中想要的操作。

    谢谢大家的帮助。

        3
  •  2
  •   bdonlan    16 年前

    在许多情况下,编译器会消除函数无法到达的结尾。您可能希望生成一个可以设置的标志以避免出现这种情况:

    void bar() {
      if (!debugFlag)
        throw int();
    }
    

    确保标志是全局的(不是静态的),这样编译器就无法证明它永远不会被写入。

    跳过罚球,

    (gdb) set debugFlag = 1
    

    以后一定要把它放回去。

        4
  •  2
  •   Nikolai Fetissov    16 年前

    扩展@justin的答案-在 bar() 功能类型 disassemble ,注意 ret 指令,设置 eip 到那个地址。

        5
  •  1
  •   laalto    16 年前

    %eip 是平台特定的,需要一些工作。只是 jump 到包含结束卷曲的行号。您需要将其与bdonlan所建议的内容结合起来,以防编译器正在优化无法访问的函数返回。

    $ cat >x.cpp
    #include <stdio.h>
    
    static volatile int debug = 0;
    
    void f() {
      if (!debug)
        throw 1;
    }
    
    int main() {
      try {
        f();
        puts("f didn't throw");
      } catch(...) {
        puts("f threw");
      }
      return 0;
    }
    
    $ g++ -g x.cpp -o x
    $ gdb x
    [...]
    (gdb) run
    Starting program: [...]/x 
    Reading symbols for shared libraries . done
    f threw
    
    Program exited normally.
    (gdb) break f
    Breakpoint 1 at 0x1e30: file x.cpp, line 6.
    (gdb) run
    Starting program: [...]/x 
    
    Breakpoint 1, f () at x.c:6
    6         if (!debug)
    (gdb) jump 8
    Continuing at 0x1e73.
    f didn't throw
    
    Program exited normally.
    
    推荐文章