2012-12-04 30 views
8

私は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のマンページを見て

  1. は、私がexp_spawnvフォークに新しいプロセスを知っていると私は* FILEを介して通信できるようになります。だから私はSIGSEGVシグナルが受信されたと思う何か悪いフォークで起こったので?

  2. バックトレースでその行(警告: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.htmlhttp://www.linuxfromscratch.org/lfs/view/development/chapter05/expect.htmlでそれを行うには本当に良い、きちんとした方法を見つけました。

おかげで再び

+0

逆アセンブリとは何ですか? – szx

+0

私はそれを私の質問に編集しました – benzeno

+0

しかし、そこには '0x00007ffff7bc8836'はありません。 – szx

答えて

4

グローバル変数TclStubs *tclStubsPtrは(tcl.hを参照)、その構造体のメンバとして定義されているアクセスTcl_ErrnoMsgからNULLときexp_spawnv試行であることを起こる:

#ifndef Tcl_ErrnoMsg 
#define Tcl_ErrnoMsg \ 
    (tclStubsPtr->tcl_ErrnoMsg) /* 128 */ 
#endif 

私は期待していないどちらも精通していませんよしかし、上記のように、初期化サブルーチン(存在する場合)を呼び出すか、手動で設定する必要があるかもしれません。

+0

ああ、それは問題かもしれない...私は** tcl.h **でそれを見つけられなかったが、** tclDecls.h **にあった。 これまでは、ソースディレクトリに 'grep -r" tclStubsPtr "*'を使ってポインタの言及や初期化を見つけました。** tclStubLib.c **で見つかった**また、 'grep'は* * libtcl8.5.so **ライブラリ。私はそのライブラリにリンクしていないことに気付くでしょう。 私の次のステップはそれにリンクして、それが何かを修正するかどうかを確認することです。もしそうでなければ、私がtclを呼び出す必要があるかどうか調べます。 – benzeno

+0

あなたは私に素晴らしいリードを与えました。おそらく 'tclStubsPtr'ポインタがヌルのままである多くの理由があります。しかし何らかの根本的な理由があっても、最大の問題はexpect/tcl環境が正しく初期化されていないことです。いくつかの掘削をした後、私は最終的に 'man libexpect'(私が始めたところ)で答えを見つけました。**著者であるDon Libes **は、ソース配布物で提供されるソースコードのプロトタイプmainとして 'exp_main_exp.c'を含んでいます。これには、tclヘッダーとexpect_tclジョイントヘッダーが含まれます。 – benzeno

+0

次に、expect/tclグローバルエンティティを強制的に初期化しました。残念ながら、これはちょっとしたハックです...私はtclを初期化したり、tclヘッダをインクルードする必要はありません。とにかく、tclがなぜ正しく初期化されないのかを決して考えていないので、私はあなたの答えを受け入れています。興味のある人は、私の質問にこれを行うサンプルメインを編集しました。 – benzeno

1

をSZXするために、私は、コンパイル警告最も懸念するだろう。インターフェイスは明らかに書き込み可能な文字列を渡す必要がありますが、文字列定数を渡します。実際に書き込むと、セグメンテーション違反が発生します。だからあなたの問題の良い候補のように見えます。 「0を返す;」最後に、私は上記の変更で(あなたのプログラムをテストしてみた、と:

char name[] = "bash"; 
FILE* file = exp_popen(name); 

更新:あなたの代わりに書き込み可能なバッファを作成しようとそれを渡すとどう

)、それは私のためにうまく動作します。おそらく、半分のインストールされたライブラリのような、あなたのシステムに何か問題がありますか? -staticとリンクすると失敗するかどうかを確認できます。これを行うと、コンパイル時にリンクされたライブラリは実行時に使用されたライブラリと同じになります(コンパイル時に実行可能ファイルに含まれるため)。 Tclの内部で定義された

+0

速い応答のためにありがとうBas、 これは警告を処理しますが、同じ問題が引き続き発生します。 – benzeno

+0

簡潔な応答のため申し訳ありませんが、これはスタックオーバーフローに関する私の最初の質問です。 私の悪いプログラミング慣行(私の見落とし)をお詫び申し上げますが、あなたは本当にそれを私の注意に向けるべきです。しかし、悲しいかな、それは主な問題を解決するものではありませんが、後に私にトラブルの世界を救うことができます。 – benzeno

+0

あまりにもそれを修正していない悪いです。ここのコメントは、いつでも削除または編集できます。 –

関連する問題