如何将调试器附加到正在运行的 Perl 进程?

发布于 2024-12-26 07:06:31 字数 1287 浏览 0 评论 0原文

我有一个正在运行的 Perl 进程被卡住了,我想用调试器查看内部,看看出了什么问题。我无法重新启动该过程。我可以将调试器附加到正在运行的进程吗?我知道我可以执行gdb -p,但是gdb对我没有帮助。我尝试过 Enbugger,但失败了:

$ perl -e 'while (1) {}'&
[1] 86836
$ gdb -p 86836
…
Attaching to process 86836.
Reading symbols for shared libraries . done
Reading symbols for shared libraries ............................. done
Reading symbols for shared libraries + done
0x000000010c1694c6 in Perl_pp_stub ()
(gdb) call (void*)Perl_eval_pv("require Enbugger;Enbugger->stop;",0)
perl(86836) malloc: *** error for object 0x3: pointer being realloc'd was not allocated
*** set a breakpoint in malloc_error_break to debug

Program received signal SIGABRT, Aborted.
0x00007fff8269d82a in __kill ()
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 (Perl_eval_pv) will be abandoned.
(gdb) 

我做错了吗?还有其他选择吗?


PS 如果您认为自己可以从附加到正在运行的进程的调试器中受益,您可以插入由 SIGUSR1 触发的调试器后门:

use Enbugger::OnError 'USR1';

然后您可以简单地kill -USR1 pid,您的进程将跳转到调试器。

I have a running Perl process that’s stuck, I’d like to poke inside with a debugger to see what’s wrong. I can’t restart the process. Can I attach the debugger to the running process? I know I can do gdb -p, but gdb does not help me. I’ve tried Enbugger, but failed:

$ perl -e 'while (1) {}'&
[1] 86836
$ gdb -p 86836
…
Attaching to process 86836.
Reading symbols for shared libraries . done
Reading symbols for shared libraries ............................. done
Reading symbols for shared libraries + done
0x000000010c1694c6 in Perl_pp_stub ()
(gdb) call (void*)Perl_eval_pv("require Enbugger;Enbugger->stop;",0)
perl(86836) malloc: *** error for object 0x3: pointer being realloc'd was not allocated
*** set a breakpoint in malloc_error_break to debug

Program received signal SIGABRT, Aborted.
0x00007fff8269d82a in __kill ()
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 (Perl_eval_pv) will be abandoned.
(gdb) 

Am I doing it wrong? Are there other options?


P.S. If you think you could benefit from a debugger attached to a running process yourself, you can insert a debugger back door triggered by SIGUSR1:

use Enbugger::OnError 'USR1';

Then you can simply kill -USR1 pid and your process will jump into the debugger.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌逼全场 2025-01-02 07:06:31

首先,如果您想使用 gdb 检查它,请使用调试 perl。

请定义“卡住”。忙或非忙等待(CPU 高或低),是否吃内存?
while 1 则忙于等待。自 5.15 以来,我通常忙于等待(无休止的循环)Perl_hfree_next_entry() 中的 HV 损坏。非忙等待通常是等待阻塞 IO 读取。

我得到了正确的结果:

`0x00007fba15ab35c1 in Perl_runops_debug () at dump.c:2266`
`2266       } while ((PL_op = PL_op->op_ppaddr(aTHX)));`

并且可以检查所有内容,比使用简单的 perl 调试器要多得多。使用非线程 Perl,您必须输入更少的内容。

`(gdb) p Perl_op_dump(PL_op)`

等等。

如果您必须使用 perl:在 pp_stub 函数内部,进入 Enbugger 运行循环不是一个好主意,您应该位于 dump.c 的主运行循环中。在所示行设置断点。

eval 上的“对象 0x3 错误”听起来像是上下文中的内部损坏,因此您应该查看 cx 和堆栈指针。可能是因为你是在一个糟糕的环境中开始的。

First, please use a DEBUGGING perl, if you want to inspect it with gdb.

Please define "stuck". Busy or non-busy waiting (high or low CPU), eating memory or not?
With while 1 it is busy waiting. I usually get busy waiting (endless cycles) on HV corruption in Perl_hfree_next_entry() since 5.15. Non-busy waiting is usually waiting on a blocking IO read.

I get the correct:

`0x00007fba15ab35c1 in Perl_runops_debug () at dump.c:2266`
`2266       } while ((PL_op = PL_op->op_ppaddr(aTHX)));`

and can inspect everything, much more than with a simple perl debugger. With a non-threaded perl you have to type less.

`(gdb) p Perl_op_dump(PL_op)`

and so on.

If you have to do with perl: Inside the pp_stub function it is not a good idea to enter the Enbugger runloop, you should be in the main runloop in dump.c. Set a breakpoint to the shown line.

"error for object 0x3" on eval sound like internal corruption in the context, so you should look at the cx and stack pointers. Probably because you started it in a bad context.

我喜欢麦丽素 2025-01-02 07:06:31

我从未使用过 gdb,但也许你可以从 strace 中得到一些有用的东西?

strace -f -s512 -p <PID>

I've never used gdb, but maybe you could get something useful out of strace?

strace -f -s512 -p <PID>
眼泪也成诗 2025-01-02 07:06:31

http://metacpan.org/pod/App::Stacktrace
“perl-stacktrace 打印给定 Perl 进程的 Perl 线程的 Perl 堆栈跟踪。对于每个 Perl 框架,都会打印完整的文件名和行号。”

http://metacpan.org/pod/App::Stacktrace
“perl-stacktrace prints Perl stack traces of Perl threads for a given Perl process. For each Perl frame, the full file name and line number are printed.”

杯别 2025-01-02 07:06:31

设置

  1. 从 CPAN 安装 Enbugger:
    cpan install Enbugger
    
  2. 将其添加到您的 .gdbinit 中:
    定义 perl_eval
        调用 (void*)Perl_eval_pv((void*)Perl_get_context(), $arg0, 0)
    结尾
    
    定义 perl_stop
        perl_eval "Enbugger->停止"
        继续
    结尾
    
    定义 perl_init
        python 导入操作系统
        python gdb.execute("set $tty=\"" + os.ttyname(0) + "\"")
        调用 open($tty, 0)
        设置 $tty_in=$
        调用 open($tty, 1)
        设置 $tty_out=$
        调用 (int) 'dup@plt'(0)
        设置 $old_stdin=$
        调用 (int) 'dup@plt'(1)
        设置 $old_stdout=$
        调用 (int) 'dup@plt'(2)
        设置 $old_stderr=$
        调用 (int) 'dup2@plt'($tty_in, 0)
        调用 (int) 'dup2@plt'($tty_out, 1)
        调用 (int) 'dup2@plt'($tty_out, 2)
        eval "perl_eval \"$ENV{PERLDB_OPTS}='TTY=%s'\"", $tty
        perl_eval“需要 Enbugger”
    结尾
    
    定义attach_perl
        附加 $arg0
        perl_init
        perl_stop
    结尾
    

    基本上,perl_init 为 perl 调试器设置终端。如果 stdin/stdout/stderr 被调试进程重定向,则如果没有上述设置,则无法与 perl 调试器交互。如果需要,您可以从备份描述符 $old_stdin/$old_stdout/$old_stderr 恢复旧的重定向。

附加到 perl 进程

  1. 通过 GDB 的 PID 附加到你的 perl 程序:

    <前><代码>(gdb)attach_perl 640368
    [启用使用libthread_db进行线程调试]
    使用主机 libthread_db 库“/lib/x86_64-linux-gnu/libthread_db.so.1”。
    __GI___select 中的 0x00007fd0b1313984 (nfds=0、readfds=0x0、writefds=0x0、 exceptfds=0x0、超时=0x7fff19c97240)位于 ../sysdeps/unix/sysv/linux/select.c:69
    69 ../sysdeps/unix/sysv/linux/select.c:没有这样的文件或目录。
    1 美元 = 7
    2 美元 = 8
    3 美元 = 9
    4 美元 = 10
    5 美元 = 11
    6 美元 = 0
    7 美元 = 1
    8 美元 = 2
    $9 = (无效*) 0x562cae6a7810
    $10 = (无效 *) 0x562cad300ee0

    从 perl5db.pl 版本 1.60 加载数据库例程
    提供编辑器支持。

    输入 h 或“h h”获取帮助,或输入“man perldebug”获取更多帮助。

    $11 = (无效 *) 0x562cad6322d0
    我的::SafeProcess::(lib/My/SafeProcess.pm:543):
    第543章1000;
    DB<1>

  2. 有时您不会在 p.3 中得到提示,因此您按 Ctrl+C 并运行 perl_stop

    输入 h 或 'h h' 获取帮助,或输入 'man perldebug' 获取更多帮助。
    
    $11 = (无效 *) 0x560577ff45a0
    ^C
    程序收到信号SIGINT,中断。
    __GI___wait4 中的 0x00007fd8f9ee25a7 (pid=626998,stat_loc=0x7fffbbeedf1c,选项=0,用法=0x0)位于 ../sysdeps/unix/sysv/linux/wait4.c:30
    30 在 ../sysdeps/unix/sysv/linux/wait4.c
    (gdb) perl_stop
    主要::((eval 20)[/home/midenok/src/mariadb/10.4/build/opt/mysql-test/mysql-test-run:5]:1):
    1:Enbugger->停止
      DB<1>
    

    只要加载了 Enbugger,您就可以随时通过 perl_stop 从 GDB 进入 perl 调试器。

  3. 您需要知道的可能就是堆栈跟踪:

    <前><代码> DB<1>;时间
    @ = DB::DB 从文件 '(eval 39)[/usr/lib/x86_64-linux-gnu/perl-base/IO/Select.pm:130]' 第 1 行调用
    $ = eval 'Enbugger->stop' 从文件 '/usr/lib/x86_64-linux-gnu/perl-base/IO/Select.pm' 第 130 行调用
    @ = IO::Select::can_read(ref(IO::Select), 1) 从文件 '/home/midenok/src/mariadb/10.4/src/mysql-test/mysql-test-run.pl' 行调用第594章
    @ = main::run_test_server(ref(IO::Socket::INET), ref(ARRAY), ref(HASH)) 从文件 '/home/midenok/src/mariadb/10.4/src/mysql-test/mysql 调用-test-run.pl' 第 485 行
    。 = main::main() 从文件'/home/midenok/src/mariadb/10.4/src/mysql-test/mysql-test-run.pl'第343行调用

    这里最新的执行点是 Select.pm 第 130 行,不要对注入的 eval 'Enbugger->stop' 感到惊讶,但有时您只会看到正常的堆栈跟踪。< /p>

从 perl 进程分离

  1. 在 perl 调试器中运行“继续”:
    <前><代码> DB<1>; c
    [从子进程 641324 分叉后分离]
    [从子进程 641326 分叉后分离]
    [fork 后与子进程分离 641328]
    [fork 后与子进程分离 641329]

  2. 按 Ctrl+C,然后按 Ctrl+D:
    <前><代码>^C
    程序收到信号SIGINT,中断。
    __GI___select 中的 0x00007fd0b1313984 (nfds=0、readfds=0x0、writefds=0x0、 exceptfds=0x0、超时=0x7fff19c97240)位于 ../sysdeps/unix/sysv/linux/select.c:69
    69 在 ../sysdeps/unix/sysv/linux/select.c
    (gdb) 退出
    与程序分离:/usr/bin/perl,进程 640368
    [下级1(进程640368)分离]

Setup

  1. Install Enbugger from CPAN:
    cpan install Enbugger
    
  2. Add this to your .gdbinit:
    define perl_eval
        call (void*)Perl_eval_pv((void*)Perl_get_context(), $arg0, 0)
    end
    
    define perl_stop
        perl_eval "Enbugger->stop"
        continue
    end
    
    define perl_init
        python import os
        python gdb.execute("set $tty=\"" + os.ttyname(0) + "\"")
        call open($tty, 0)
        set $tty_in=$
        call open($tty, 1)
        set $tty_out=$
        call (int) 'dup@plt'(0)
        set $old_stdin=$
        call (int) 'dup@plt'(1)
        set $old_stdout=$
        call (int) 'dup@plt'(2)
        set $old_stderr=$
        call (int) 'dup2@plt'($tty_in, 0)
        call (int) 'dup2@plt'($tty_out, 1)
        call (int) 'dup2@plt'($tty_out, 2)
        eval "perl_eval \"$ENV{PERLDB_OPTS}='TTY=%s'\"", $tty
        perl_eval "require Enbugger"
    end
    
    define attach_perl
        attach $arg0
        perl_init
        perl_stop
    end
    

    Basically perl_init sets up terminal for perl debugger. If stdin/stdout/stderr was redirected by the debugged process you cannot interact perl debugger without the above setup. You can recover old redirections from the backup descriptors $old_stdin/$old_stdout/$old_stderr if needed.

Attach to perl process

  1. Attach to your perl program by PID from GDB:

    (gdb) attach_perl 640368
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    0x00007fd0b1313984 in __GI___select (nfds=0, readfds=0x0, writefds=0x0, exceptfds=0x0, timeout=0x7fff19c97240) at ../sysdeps/unix/sysv/linux/select.c:69
    69      ../sysdeps/unix/sysv/linux/select.c: No such file or directory.
    $1 = 7
    $2 = 8
    $3 = 9
    $4 = 10
    $5 = 11
    $6 = 0
    $7 = 1
    $8 = 2
    $9 = (void *) 0x562cae6a7810
    $10 = (void *) 0x562cad300ee0
    
    Loading DB routines from perl5db.pl version 1.60
    Editor support available.
    
    Enter h or 'h h' for help, or 'man perldebug' for more help.
    
    $11 = (void *) 0x562cad6322d0
    My::SafeProcess::(lib/My/SafeProcess.pm:543):
    543:        $millis++ if $millis < 1000;
      DB<1>
    
  2. Sometimes you will not get prompt in p.3, so you press Ctrl+C and run perl_stop:

    Enter h or 'h h' for help, or 'man perldebug' for more help.
    
    $11 = (void *) 0x560577ff45a0
    ^C
    Program received signal SIGINT, Interrupt.
    0x00007fd8f9ee25a7 in __GI___wait4 (pid=626998, stat_loc=0x7fffbbeedf1c, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:30
    30      in ../sysdeps/unix/sysv/linux/wait4.c
    (gdb) perl_stop
    main::((eval 20)[/home/midenok/src/mariadb/10.4/build/opt/mysql-test/mysql-test-run:5]:1):
    1:      Enbugger->stop
      DB<1>
    

    Any time you can get from GDB to perl debugger by perl_stop as long as Enbugger is loaded.

  3. All you need to know is probably the stack trace:

      DB<1> T
    @ = DB::DB called from file '(eval 39)[/usr/lib/x86_64-linux-gnu/perl-base/IO/Select.pm:130]' line 1
    $ = eval 'Enbugger->stop' called from file '/usr/lib/x86_64-linux-gnu/perl-base/IO/Select.pm' line 130
    @ = IO::Select::can_read(ref(IO::Select), 1) called from file '/home/midenok/src/mariadb/10.4/src/mysql-test/mysql-test-run.pl' line 594
    @ = main::run_test_server(ref(IO::Socket::INET), ref(ARRAY), ref(HASH)) called from file '/home/midenok/src/mariadb/10.4/src/mysql-test/mysql-test-run.pl' line 485
    . = main::main() called from file '/home/midenok/src/mariadb/10.4/src/mysql-test/mysql-test-run.pl' line 343
    

    Here the latest execution point is Select.pm line 130, don't get surprised by injected eval 'Enbugger->stop', but sometimes you will see just a normal stack trace.

Detach from perl process

  1. Run "continue" in perl debugger:
      DB<1> c
    [Detaching after fork from child process 641324]
    [Detaching after fork from child process 641326]
    [Detaching after fork from child process 641328]
    [Detaching after fork from child process 641329]
    
  2. Press Ctrl+C and then Ctrl+D:
    ^C
    Program received signal SIGINT, Interrupt.
    0x00007fd0b1313984 in __GI___select (nfds=0, readfds=0x0, writefds=0x0, exceptfds=0x0, timeout=0x7fff19c97240) at ../sysdeps/unix/sysv/linux/select.c:69
    69      in ../sysdeps/unix/sysv/linux/select.c
    (gdb) quit
    Detaching from program: /usr/bin/perl, process 640368
    [Inferior 1 (process 640368) detached]
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文