我忙于一个项目,我必须在bash或ssh中自动化一些进程,所以我决定使用libexpect.so库。如果你不知道libexpect是什么,它提供了一个我可以在C++程序中使用的期望扩展,期望只是一个可以为ssh之类的东西运行自动化脚本的程序。所以我可以执行一个脚本,试图在某处ssh ...当密码提示被发现,期望我可能已经给予期待密码发送。为什么我在使用libexpect.so的简单C++程序中出现分段错误?
我的问题是,当我运行一个程序,甚至是一个非常简单的程序时,我得到一个分段错误,我用gdb缩小了libexpect.so中一个名为exp_spawnv的函数。
我知道我已经把库链接起来了,它编译得很好,事实上,当我在ubuntu中编译和运行时,并不存在整个问题,但是在我的arch linux安装中,我得到了细节错误,后来。我之所以在拱门上架设它,是因为我希望最终可以在大多数发行版上构建项目。
我的想法是,在我的拱安装有权限,当exp_spawnv函数被调用,可能是一个管道,叉子或任何其他权限。
为了证明我没有做一些简单的事情,下面是一个简单的main.cpp用于说明目的。
#include <tcl8.5/expect.h>
int main()
{
FILE* file = exp_popen("bash");
}
所以它只是有史以来最简单的期望计划。这里是我编译和链接它。
$克++ -ggdb -c main.cpp中
main.cpp中:在函数 '诠释主()':
main.cpp中:5:32:警告:弃用转换从字符串常量 '字符*'[-Wwrite串]
$克++ main.o -lexpect -o mainprog
所以我得到我的可执行mainprog ...只是运行,这将给我一个分段错误,没有别的。
如果我在gdb中运行mainprog,它会告诉我exp_spawnv中有seg故障。这是我在最后的backtrace中在gdb中做的。
(GDB)运行
启动程序:/ home/user中/ testlibexpect/mainprog
警告:无法加载Linux的vdso.so.1共享库的符号。
你需要“设置solib-search-path”或“set sysroot”吗?
程序接收到的信号SIGSEGV,分段错误。
0x00007ffff7bc8836 in exp_spawnv()from/usr/lib/libexpect。所以
(GDB)从/usr/lib/libexpect.so
1 0x00007ffff7bc8cb4回溯
0 exp_spawnv 0x00007ffff7bc8836()在exp_spawnl()从/ usr/LIB/libexpect。所以
2 0x00007ffff7bc8d01在exp_popen()从/usr/lib/libexpect.so
3在主在main.cpp中0x000000000040069e():5
两件事关注我。
看着libexpect的手册页,我知道exp_spawnv分叉一个新的进程,我可以通过FILE *进行通信。所以我猜SIGSEGV信号是因为叉子发生故障而收到的?
该行(警告:无法为linux-vdso.so.1加载共享库符号)在回溯中看起来很腥吗?
因此,总之,我的问题是我应该看看解决这个问题?我曾尝试从源代码构建期望的库,并通过arch包管理器pacman获取它...问题依然存在,因此如果知道我的意思,我认为库构建不会损坏。
编辑:根据我所做的研究,我的担忧点2不是问题,只是美容。
Eclipse中的拆卸低于:
00007ffff7bc87c6: mov 0x20c68b(%rip),%rax # 0x7ffff7dd4e58
00007ffff7bc87cd: mov (%rax),%rax
00007ffff7bc87d0: test %rax,%rax
00007ffff7bc87d3: je 0x7ffff7bc87d7 <exp_spawnv+935>
00007ffff7bc87d5: callq *%rax
00007ffff7bc87d7: mov %r12,%rsi
00007ffff7bc87da: mov %rbp,%rdi
00007ffff7bc87dd: callq 0x7ffff7bb2330 <[email protected]>
00007ffff7bc87e2: callq 0x7ffff7bb1720 <[email protected]>
00007ffff7bc87e7: mov 0x24(%rsp),%edi
00007ffff7bc87eb: mov %rax,%rsi
00007ffff7bc87ee: mov $0x4,%edx
00007ffff7bc87f3: xor %eax,%eax
00007ffff7bc87f5: callq 0x7ffff7bb1910 <[email protected]>
00007ffff7bc87fa: mov $0xffffffff,%edi
00007ffff7bc87ff: callq 0x7ffff7bb23d0 <[email protected]>
00007ffff7bc8804: nopl 0x0(%rax)
00007ffff7bc8808: xor %eax,%eax
00007ffff7bc880a: movl $0x0,0x20dd3c(%rip) # 0x7ffff7dd6550
00007ffff7bc8814: callq 0x7ffff7bb1700 <[email protected]>
00007ffff7bc8819: xor %eax,%eax
00007ffff7bc881b: callq 0x7ffff7bb2460 <[email protected]>
00007ffff7bc8820: lea -0x1c97(%rip),%rdi # 0x7ffff7bc6b90
00007ffff7bc8827: callq 0x7ffff7bb2540 <[email protected]>
00007ffff7bc882c: mov 0x20c555(%rip),%rax # 0x7ffff7dd4d88
00007ffff7bc8833: mov (%rax),%rax
00007ffff7bc8836: mov 0x410(%rax),%rdi
答案,我想出了
下面是我最终想出了解决方案,我已经接受了SZX的答案,因为它导致我失望一旦我知道我在找什么,这条路很平凡。
//do not use TCL stubs as this is a main
#undef USE_TCL_STUBS
#include <iostream>
using std::cout;
using std::endl;
//headers that must be included when using expectTcl as an extension to c++ program
#include <stdio.h>
#include <stdlib.h>
#include <expectTcl/tcl.h>
#include <expectTcl/expect_tcl.h>
#include <expectTcl/expect.h>
//enums representing cases of what expect found in loop
enum{FOUNDSEARCH, PROMPT};
int main()
{
/* initialise expect and tcl */
Tcl_Interp *interp = Tcl_CreateInterp();
if(Tcl_Init(interp) == TCL_ERROR)
{
cout << "TCL failed to initialize." << endl;
}
if(Expect_Init(interp) == TCL_ERROR)
{
cout << "Expect failed to initialize." << endl;
}
/* end of intialisation procedure */
//open a shell with a pipe
char shellType[] = "sh";
FILE* fp = exp_popen(shellType);
//should we exit from the loop which is studying sh output
bool shouldBreak = false;
//did we find the pwd
bool foundSearch = false;
//does it look like expect is working
bool expectWorking = false;
//did we receive a prompt...therefore we should send a command
bool receivedPrompt = false;
while(shouldBreak == false)
{
switch(exp_fexpectl(fp,
exp_glob, "/tools/test*", FOUNDSEARCH, //different
exp_glob,"# ", PROMPT, //cases are shown here
exp_end)) //that the expect loop could encounter
{
case FOUNDSEARCH:
foundSearch = true;
break;
case PROMPT:
if (receivedPrompt)
{
shouldBreak = true;
expectWorking = true;
}
else
{
receivedPrompt = true;
fprintf(fp, "%s\r", "pwd");
}
break;
case EXP_TIMEOUT:
shouldBreak = true;
break;
case EXP_EOF:
shouldBreak = true;
break;
}
//cout << "exp_match : " << exp_match << endl;
}
cout << endl;
if (foundSearch)
{
cout << "Expect found output of pwd" << endl;
}
else
{
cout << "Expect failed to find output of pwd" << endl;
}
if(expectWorking)
{
cout << "The expect interface is working" << endl;
}
else
{
cout << "The expect interface is not working" << endl;
}
cout << "The test program successfully reached the end" << endl;
}
我在这里所做的所有显示如何初始化expect/tcl来防止我曾经说过的szx问题。然后,我只是做了一个典型的期望问题,我几乎说,如果shell提示你输入发送密码。然后,如果它给你当前目录期望正在工作。这种结构对于类似ssh的应用程序非常有用。假如你想在某处自动化sshing,做一些事情然后离开。特别是如果你想做几次,你不想确认每个主机的真实性,并在每次输入密码。
注意,我从来没有出于某种原因做这个Ubuntu的 ...可能是因为我没有从源代码编译它,只是使用apt-get
。但是,我的项目需要我从源代码构建,所以我发现了一个非常好的,整洁的方式来做到这一点http://www.linuxfromscratch.org/lfs/view/development/chapter05/tcl.html和http://www.linuxfromscratch.org/lfs/view/development/chapter05/expect.html ...事实上,整个网站看起来非常有用。再次
由于SZX
反汇编说什么? – szx
我把它编辑成我的问题 – benzeno
但是里面没有'0x00007ffff7bc8836',地址是否改变? – szx