我有一个小的Perl程序。该程序加载一个模块。该模块使用XSLoader加载.so文件。这个Perl在Linux上运行,使用gcc和notification.flags = Notification.FLAG_INSISTENT;
构建,随后是.so文件。我可以重新编译。
执行Perl程序时,如何追踪.so文件中的C函数?我需要按照它们运行的顺序知道函数的名称。拥有函数参数也很好。
答案 0 :(得分: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
请注意,我们在libmylib.so
中添加了调试符号,方法是-g
切换到gcc
。
现在,我们可以创建一个.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',
);
请注意,我们使用Mytest.so
请求调试符号(对于OPTIMIZE => '-g'
共享对象),并使用libmylib.so
通知其他共享库LIBS
的位置WriteMakefile()
的论据。
然后我们编译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;
我们可以知道在我们的测试脚本gdb
上运行p.pl
:
$ 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) {
依旧......