私はbashやsshでいくつかのプロセスを自動化しなければならないプロジェクトに忙しくて、libexpect.soライブラリを使うことにしました。 libexpectが何であるかわからない場合は、C++プログラムで使用できるexpectエクステンションを提供しています.sshのようなものに対して自動スクリプトを実行できるプログラムにすぎません。だから私はどこかでsshしようとするスクリプトを実行することができます。libexpect.soを使用している単純なC++プログラムでセグメンテーション違反が発生するのはなぜですか?
私の問題は、プログラムを実行すると、本当に単純なものであっても、gdbを使って、expexameという名前の関数にexp_spawnvを絞り込んだセグメンテーション違反が発生するということです。
私はライブラリの権利をリンクしていることは分かっていますが、うまくコンパイルされ、ubuntuでコンパイルして実行すると問題はありませんが、私のarch Linuxのインストールでは、後で。私がアーチ上にビルドする理由は、ほとんどのディストリビューションでプロジェクトをビルド可能にしたいからです。
私のアーチインストールでは、exp_spawnv関数が呼び出されたときに失敗するパーミッションがあります。おそらくパイプ、フォークなどです。
私が何かファンキーなことをしていないことを証明するために、ここでは簡単なmain.cppを図解のために示します。
#include <tcl8.5/expect.h>
int main()
{
FILE* file = exp_popen("bash");
}
これはこれまでに作成された最も簡単なプログラムです。ここで私はそれをコンパイルしてリンクしています。
$ G ++ -ggdb -C main.cppに
main.cppに:機能において 'メインINT()':
main.cppに:5:32:警告:非推奨の変換'CHAR *' への定数文字列から[-Wwrite-文字列]
$ G ++ main.o -lexpect -o mainprog
私は実行可能なmainprogを手に入れました。ちょうどそれが私にセグメンテーションフォールトと他に何も与えません。
gdbでmainprogを実行すると、exp_spawnvにsegフォルトがあることがわかります。ここで私は最後にバックトレースとgdbで何をしたのですか?
(GDB)プログラムを起動する
を実行します。/ home /ユーザー/ testlibexpect/mainprog
警告:のlinux-vdso.so.1のための共有ライブラリのシンボルをロードできませんでした。
"set solib-search-path"または "set sysroot"が必要ですか?
プログラム受信信号SIGSEGV、セグメンテーションフォルト。
exp_spawnv()内の0x00007ffff7bc8836は/ usr/lib/libexpectです。そう
(GDB)exp_spawnlで/usr/lib/libexpect.so
1 0x00007ffff7bc8cb4からバックトレースexp_spawnvで
0 0x00007ffff7bc8836()()は/ usr/LIB/libexpectから。そうexp_popenで
2 0x00007ffff7bc8d01()main.cppにで主に
3 0x000000000040069e()/usr/lib/libexpect.soから:5
2つのことが私に関係します。 libexpectのマンページを見て
- は、私がexp_spawnvフォークに新しいプロセスを知っていると私は* FILEを介して通信できるようになります。だから私はSIGSEGVシグナルが受信されたと思う何か悪いフォークで起こったので?
バックトレースでその行(警告:linux-vdso.so.1の共有ライブラリシンボルを読み込めませんでした)が怪しいですか?
要約すると、この問題を解決するにはどうすればよいですか?私はsourceからexpectライブラリを構築しようとしました。アークパッケージマネージャーのpacmanと一緒にそれを取得してみました...問題は解決しないので、私が何を意味するのか知っていれば、ライブラリビルドが壊れているとは思われません。
EDIT:私の心配のポイント2は、私がやった研究によれば、化粧品だけでは問題ではありません。
日食から解体は以下の通りです:
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 <expDiagLog[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;
}
私はここでやったすべては、私がSZXが話したことを持っていた問題を回避することを期待/ TCLを初期化する方法を示しています。それでは、シェルが入力を促してpwdを送信した場合、私はかなり言いました。それから、あなたに現在のディレクトリが与えられていれば、expectが動作しています。この種の構造は、sshのようなものには非常に便利です。どこかでsshingを自動化したい場合は、何かをしてからそこから抜け出してください。特にあなたが数百回それをしたい場合は、すべてのホストの真正性を確認し、毎回パスワードを入力したくない場合。私はソースからビルドするだけapt-get
を使用していなかったので、私はおそらく...何らかの理由でUbuntuのにこれをしなければならなかったことはありません
注意。しかし、私のプロジェクトではソースからビルドする必要があるので、http://www.linuxfromscratch.org/lfs/view/development/chapter05/tcl.htmlとhttp://www.linuxfromscratch.org/lfs/view/development/chapter05/expect.htmlでそれを行うには本当に良い、きちんとした方法を見つけました。
おかげで再び
逆アセンブリとは何ですか? – szx
私はそれを私の質問に編集しました – benzeno
しかし、そこには '0x00007ffff7bc8836'はありません。 – szx