2016-07-30 13 views
2

私はWindowsからLinuxにプログラムを移植しようとしています。
Linux上に「本物」のReadProcessMemoryがないことがわかったときに問題が発生しました。代替案を探して、強力なプロセスデバッガであるptraceが見つかりました。
私はすぐにプログラムで使用する前に、ptraceをテストするために、C++で小さなコンソールアプリケーションを2つコーディングしました。Linux:プロセス(SIGSTOP)を停止/一時停止せずにptraceを使用する方法はありますか?

でTestApp

これはtraceeあります。 50ミリ秒ごとに2つの整数を印刷し、毎回その値を1ずつ増加させます。

#include <QCoreApplication> 
#include <QThread> 
#include <iostream> 

using namespace std; 

class Sleeper : public QThread 
{ 
public: 
    static void usleep(unsigned long usecs){QThread::usleep(usecs);} 
    static void msleep(unsigned long msecs){QThread::msleep(msecs);} 
    static void sleep(unsigned long secs){QThread::sleep(secs);} 
}; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    int value = 145; 
    int i = 0; 

    do { 
    cout << "i: " << i << " " << "Value: " << value << endl; 
    value++; 
    i++; 
    Sleeper::msleep(50); 
    } while (true); 

    return a.exec(); 
} 

MemoryTest

これはトレーサです。プロセス名を尋ねて、コマンドpidof -sを使用してPIDを取得すると、ptraceがプロセスにアタッチされ、メモリアドレスの値が500ミリ秒ごとに10回取得されます。

#include <QCoreApplication> 
#include <QThread> 
#include <iostream> 
#include <string> 
#include <sys/ptrace.h> 
#include <errno.h> 

using namespace std; 

class Sleeper : public QThread 
{ 
public: 
    static void usleep(unsigned long usecs){QThread::usleep(usecs);} 
    static void msleep(unsigned long msecs){QThread::msleep(msecs);} 
    static void sleep(unsigned long secs){QThread::sleep(secs);} 
}; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    char process_name[50]; 
    cout << "Process name: "; 
    cin >> process_name; 

    char command[sizeof(process_name) + sizeof("pidof -s ")]; 
    snprintf(command, sizeof(command), "pidof -s %s", process_name); 

    FILE* shell = popen(command, "r"); 
    char pidI[sizeof(shell)]; 
    fgets(pidI, sizeof(pidI), shell); 
    pclose(shell); 

    pid_t pid = atoi(pidI); 
    cout << "The PID is " << pid << endl; 

    long status = ptrace(PTRACE_ATTACH, pid, NULL, NULL); 
    cout << "Status: " << status << endl; 
    cout << "Error: " << errno << endl; 

    unsigned long addr = 0x; // Example address, not the true one 
    int i = 0; 
    do { 
    status = ptrace(PTRACE_PEEKDATA, pid, addr, NULL); 
    cout << "Status: " << status << endl; 
    cout << "Error: " << errno << endl; 
    i++; 
    Sleeper::msleep(500); 
    } while (i < 10); 

    status = ptrace(PTRACE_DETACH, pid, NULL, NULL); 
    cout << "Status: " << status << endl; 
    cout << "Error: " << errno << endl; 

    return a.exec(); 
} 

すべてが正常に動作しますが、ptraceはそれから外れるまででTestAppは(SIGSTOP)一時停止されています。
また、プロセスにアタッチすると、ステータスは0、エラーは2です。メモリアドレス値を最初に取得しようとすると、ステータス-1とエラー3で失​​敗します。これは正常ですか?
ptraceがSIGSTOPシグナルをプロセスに送信しないようにする方法はありますか? は、私はすでに代わりPTRACE_ATTACHPTRACE_SEIZEを使用してみましたが、それは動作しません:状態-1とエラー3

更新:を前にMemoryTestでSleeperの使用「を行い、一方で」ループは最初の問題を修正秒、ミリ秒またはマイクロ秒の値が0であっても、メモリアドレス値を取得できます。なぜですか?

答えて

1

多くの研究の後、私は、プロセスを停止することなくptraceを使用する方法がないことをかなり確信しています。
私は実際のReadProcessMemory相当物を見つけました。これは、より簡単なprocess_vm_readvと呼ばれています。

私の(前の)状況にいる人を助けるためにコードを投稿しています。

この美しい機能でMemoryTestをコーディングする彼の助けを借りて多くのお礼ありがとうmkrautz

#include <QCoreApplication> 
#include <QThread> 
#include <sys/uio.h> 
#include <stdint.h> 
#include <stdio.h> 
#include <errno.h> 
#include <string.h> 
#include <iostream> 

using namespace std; 

class Sleeper : public QThread 
{ 
public: 
    static void usleep(unsigned long usecs){QThread::usleep(usecs);} 
    static void msleep(unsigned long msecs){QThread::msleep(msecs);} 
    static void sleep(unsigned long secs){QThread::sleep(secs);} 
}; 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    char process_name[50]; 
    cout << "Process name: "; 
    cin >> process_name; 

    char command[sizeof(process_name) + sizeof("pidof -s ")]; 
    snprintf(command, sizeof(command), "pidof -s %s", process_name); 

    FILE* shell = popen(command, "r"); 
    char pidI[sizeof(shell)]; 
    fgets(pidI, sizeof(pidI), shell); 
    pclose(shell); 

    pid_t pid = atoi(pidI); 

    cout << "The PID is " << pid << endl; 

    if (pid == 0) 
     return false; 

    struct iovec in; 
    in.iov_base = (void *) 0x; // Example address, not the true one 
    in.iov_len = 4; 

    uint32_t foo; 

    struct iovec out; 
    out.iov_base = &foo; 
    out.iov_len = sizeof(foo); 

    do { 
     ssize_t nread = process_vm_readv(pid, &out, 1, &in, 1, 0); 
     if (nread == -1) { 
      fprintf(stderr, "error: %s", strerror(errno)); 
     } else if (nread != in.iov_len) { 
      fprintf(stderr, "error: short read of %li bytes", (ssize_t)nread); 
     } 
     cout << foo << endl; 
     Sleeper::msleep(500); 
    } while (true); 

    return a.exec(); 
} 
2

ダヴィデ、

を使用すると、/ procファイルシステムを見たことがありますか?これには、完全なプロセス空間を覗くために使用できるメモリマップファイルが含まれています。スペースに書き込んでブレークポイントを設定することもできます。/procには他にも豊富な情報があります。

PTRACE_CONTコマンドを使用すると、プロセスを続行できます。一般に、デバッガが接続すると、ターゲットはPTRACE_ATTACHで一時停止されます。

マニュアルページには、PTRACE_SIEZEがプロセスを一時停止してはならないと記載されています。どのような味とバージョンのLinuxを使用していますか? PTRACE_SIEZEはしばらくお待ちしていますので、どうしてあなたが問題を抱えているのか分かりません。

addrの値は0x12345に設定されています。これはターゲットスペース内の有効なアドレスですか?それとも単なる例ですか?関心のあるスタックアドレス(&値)は、2つのプロセス間でどのように通信されますか?

私はリターンコードについてあまりよく分かりません。一般に0はすべてがうまくいることを意味し、errnoは最後のエラーからの二日酔い値に過ぎないことがあります。

--Matt

+0

あなたの答えをありがとうございました。もっと簡単な方法を使いたいので、私は/ procを見ていませんでした。可能でない場合は、メモリマップファイルを試してみます。私はDebian 8 x64を使用していますが、これは問題ではありません。私の推測では、 'PTRACE_SEIZE'は' PTRACE_ATTACH'とは別の方法で使用する必要がありますが、特定のドキュメントは見つかりません。 –

+0

2つのコメントを申し訳ありません。コメントを編集しましたが、5分後には更新できなくなりました。 'addr'値は単なる例であり、正しいものはうまくいきます。エラーコードについては、プログラムが正常に動作するため、問題ではありません。 –

+0

コード内のあなたのコメントは、アドレスが例であると言っています。 Stack Overflowで私の評判を築こうとしているので、それが役に立ったら、私の答えを「受け入れてください」。 ptrace呼び出しが/ procファイルを操作するより簡単になることは間違いありません。しかし、/ proc領域にはたくさんの情報があります。あなたがLinuxのデバッグとプロセスの構造について学んでいるなら、それは研究に有益な領域になります。 PTRACE_CONTはプログラムで動作しましたか? –

関連する問題