我该如何跟踪一个XS .so文件?

13

我有一个小的Perl程序。该程序加载了一个模块,该模块使用XSLoader加载了一个.so文件。这个Perl程序在Linux上运行,并使用gcc和-DDEBUGGING进行构建,因此.so文件也是如此。我可以重新编译。

当执行Perl程序时,如何跟踪.so文件中的C函数?我需要知道函数名称以及它们运行的顺序。最好也能获取函数参数。


1
你可能会在perlhacktips中找到一些相关信息。 - Håkon Hægland
你需要使用像 gdb 这样的低级调试器。 - nwellnhof
如果你只对系统调用感兴趣,你可以使用strace。 - FelixEnescu
似乎可以使用gdb实现,参见如何在GDB中自动打印每个执行的行直到达到给定断点?及其中被接受的答案。 - Håkon Hægland
1个回答

10

这是使用gdb来步入共享库的示例。我正在使用Linux(Ubuntu 18.04)。

我首先使用perlbrew安装了Perl的调试版本:

perlbrew install perl-5.26.2 --as=5.26.2d -DDEBUGGING
perlbrew use 5.26.2d

然后,我在文件夹/home/hakon/mylib中创建了一个共享库(为了测试目的而被简化成非常基础的内容):

mylib.c

这个函数是从perlxstut的示例3改编而来:

#include <math.h>
#include "myclib.h"
double my_clib_function( double arg ) {
    if (arg > 0.0) {
        arg = floor(arg + 0.5);
    } else if (arg < 0.0) {
        arg = ceil(arg - 0.5);
    } else {
        arg = 0.0;
    }
    return arg;
}

myclib.h:

double my_clib_function( double arg );

然后我创建了共享库libmylib.so

gcc -g -c -fpic mylib.c
gcc -g -shared -o libmylib.so mylib.o

请注意,我们使用-g开关将调试符号包含在libmylib.so中。

现在,我们可以创建一个.xs文件,该文件将调用共享库函数(位于文件夹/home/hakon/myxstest中):

Mytest.xs

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "myclib.h"

MODULE = Mytest     PACKAGE = Mytest        

void
wrapper(arg)
        double  arg
    CODE:
        arg = my_clib_function( arg);
    OUTPUT:
        arg

接下来需要将XS文件链接到Perl包名:

lib/Mytest.pm:

package Mytest;
use 5.022001;
use strict;
use warnings;

require Exporter;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw();
our $VERSION = '0.01';

require XSLoader;
XSLoader::load('Mytest', $VERSION);

接下来,我们需要一个像ExtUtils::MakeMaker这样的构建系统来编译XS文件(生成另一个共享库):

Makefile.PL:

use 5.022001;
use ExtUtils::MakeMaker;
my $lib_dir = '/home/hakon/mylib';
WriteMakefile(
    NAME              => 'Mytest',
    VERSION_FROM      => 'lib/Mytest.pm', 
    PREREQ_PM         => {},
    ABSTRACT_FROM     => 'lib/Mytest.pm',
    AUTHOR            => 'Håkon Hægland <xxx.yyy@gmail.com>',
    LIBS              => ["-L$lib_dir -lmylib"],
    INC               => "-I. -I$lib_dir",
    OPTIMIZE          => '-g',
);

请注意,我们使用OPTIMIZE => '-g'请求调试符号(用于Mytest.so共享对象),并通过在WriteMakefile()中使用LIBS参数来通知其他共享库libmylib.so的位置。

然后,我们编译XS代码:

perl Makefile.PL
make

最后,我们编写一个小的Perl测试脚本:

p.pl

#! /usr/bin/env perl
use feature qw(say);
use strict;
use warnings;
use ExtUtils::testlib;
use Mytest;

my $res = 3.5;
Mytest::wrapper( $res ); # <-- Warning: modifies $res in place !
say $res;

我们可以在测试脚本 p.pl 上运行 gdb

$ gdb -q --args perl p.pl
Reading symbols from perl...done.
我们在XS文件的14行设置断点:
(gdb) break Mytest.xs:14
No source file named Mytest.xs.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (Mytest.xs:14) pending.

然后运行脚本:

(gdb) run
Starting program: /home/hakon/perlbrew/perls/5.26.2d/bin/perl p.pl
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, XS_Mytest_wrapper (cv=0x555555bdc860) at Mytest.xs:14
14          arg = my_clib_function( arg);

现在我们已经停在XS文件中将调用共享库函数的点上。如果需要,我们可以查看将要传递的参数:

(gdb) p arg
$1 = 3.5

然后进入共享库:

(gdb) s
my_clib_function (arg=3.5) at mylib.c:5
5       if (arg > 0.0) {
翻译中...

等等……


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接