【问题标题】:gdb freezes in mallocgdb 在 malloc 中冻结
【发布时间】:2016-12-31 16:16:15
【问题描述】:

假设我有一些这样的 C 程序:

#include <stdlib.h>
#include <stdbool.h>

int main()
{
    while (true) {
        void *p = malloc(1000);
        free(p);
    }
    return 0;
}

我用gdb 附加到它,就像gdb a.out PID 这样。 gdb 成功附加到它,但我尝试做类似call printf("bla bla bla") gdb 冻结,如果我按Ctrl^C 我得到这个:

(gdb) call printf("bla bla bla")
^C
Program received signal SIGINT, Interrupt.
__lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
95  ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: No such file or directory.
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(malloc) will be abandoned.
When the function is done executing, GDB will silently stop.

我想这是因为我的a.out 正在创建一个对象并在malloc.c 中获得了一个锁,此时我与gdb 连接并尝试使用malloc 创建字符串“bla bla bla”。

我的问题是如何检测到我在malloc.c 中并让我的程序完成此执行?我不需要在命令行中执行此操作,而是使用某种 gdb 脚本(我只能在 gdb 中使用 -ex 选项执行命令)。

【问题讨论】:

  • 这对我有用...printfcompleted。我尝试运行 gdb ./sample.out 并附加到正在运行的进程。
  • @IshayPeled 我认为你很幸运,sample.out 目前还没有执行malloc。您可以尝试重复多次。
  • 从 gdb 调用函数是一种可疑的做法,尤其是从标准库中。一个原因是你刚刚经历的。在调试时,您希望程序处于静态状态以便您可以检查它,调用可能改变状态的函数对于调试来说适得其反。我建议找到一种不同的方法来解决您的问题。
  • @Art 但据我所知,在gdb 中调用一些函数是我可以在运行进程中注入一些代码的唯一方法。你知道更好的方法吗?
  • @Dima 对 - 我尝试了 10 次,但最终还是被挂了。请参阅我的答案以了解可能的 WA

标签: c linux gdb


【解决方案1】:

您被冻结的原因可能是您的程序持有的锁,printf 也需要该锁。当您尝试获取它两次时 - 您失败了。

一种可能的 WA 是在将程序中断为 call printf 时,就在您进行调用之前,键入 finish - 这将导致当前函数完成并返回到主框架。这将确保在您调用 printf 之前锁是空闲的。

【讨论】:

  • 是的,但这里的主要问题是我如何才能理解我在malloc 内部并且我需要调用完成?我在另一个程序中将这个gdb 作为子进程运行,所以我无法访问控制台,需要了解使用-ex 执行命令(或者我可以编写一些.gdbinit 脚本并在那里定义我的函数)。
  • 好吧,如果有趣的代码在你在这里描述的外循环(主函数)中,那不是问题 - 外循环忽略完成。
  • 酷,我不知道,谢谢)。但是问题仍然存在,因为我的实际项目有点复杂(实际上它是一个 ruby​​ 解释器:))并且它可以在一些不是主要功能的“无限”循环内(我使用引号是因为它在我的过程中运行正在运行)。
  • 你可以试试while $_any_caller_matches(".*malloc.*") &lt;newline&gt; finish &lt;newline&gt; end
  • @Dima 你可以从sourceware.org/git/… 得到$_any_caller_matches;下载文件并使用 gdb source 命令将其读入。我已经验证,至少对于您的演示程序,while $_any_caller_matches(".*malloc.*") &lt;newline&gt; finish &lt;newline&gt; end 代码有效;它将匹配 __GI___libc_malloc_int_malloc 等函数。
【解决方案2】:

如果“完成”解决方案对您不起作用。这是另一个想法。

您可以在中断程序时检查您是否在 malloc 中。根据布尔输入/输出,您跳过调用打印命令。这是一个工作示例。

# gdb script: pygdb-logg.gdb
# easier interface for pygdb-logg.py stuff
# from within gdb: (gdb) source -v pygdb-logg.gdb
# from cdmline: gdb -x pygdb-logg.gdb -se test.exe

# first, "include" the python file:
source -v pygdb-logg.py

# define shorthand for inMalloc():
define inMalloc
  python inMalloc()
end

相关的python文件:

# gdb will 'recognize' this as python
#  upon 'source pygdb-logg.py'
# however, from gdb functions still have
#  to be called like:
#  (gdb) python print logExecCapture("bt")

import sys
import gdb
import os

def logExecCapture(instr):
  # /dev/shm - save file in RAM
  ltxname="/dev/shm/c.log"

  gdb.execute("set logging file "+ltxname) # lpfname
  gdb.execute("set logging redirect on")
  gdb.execute("set logging overwrite on")
  gdb.execute("set logging on")
  gdb.execute("bt")
  gdb.execute("set logging off")

  replyContents = open(ltxname, 'r').read() # read entire file
  return replyContents

# in malloc?
def inMalloc():
  isInMalloc = -1;
  # as long as we don't find "Breakpoint" in report:
  while isInMalloc == -1:
    REP=logExecCapture("n")
#Look for calls that have '_malloc' in them 
    isInMalloc = REP.find("_malloc")
    if(isInMalloc != -1):
#       print ("Malloc:: ", isInMalloc, "\n", REP)
       gdb.execute("set $inMalloc=1")
       return True
    else:
#       print ("No Malloc:: ", isInMalloc, "\n", REP)
       gdb.execute("set $inMalloc=0")
       return False

gdb -x pygdb-logg.gdb -se test.exe

从命令行或脚本,

(gdb) inMalloc
(gdb) print $inMalloc

来自实际测试程序:

Program received signal SIGINT, Interrupt.
0x00007ffff7a94dba in _int_malloc (av=<optimized out>, bytes=1) at malloc.c:3806
3806    malloc.c: No such file or directory.
(gdb) inMalloc
(gdb) if $inMalloc
 >print $inMalloc
 >end
$1 = 1

我相信您的脚本可以使用类似的“if”结构来执行/不执行 printf

大部分内容是从here 中删除的

【讨论】:

  • 谢谢!尽管我需要做一些更复杂的事情,但你的方法给了我一些有用的想法。
猜你喜欢
  • 1970-01-01
  • 2020-08-14
  • 2012-01-02
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多