4

mprotect()を使用して、メモリのブロックへのアクセスを制限するプログラムを作成しています。メモリが要求されると、signal()呼び出しを使用してリッスンするSIGSEGVがスローされます。

SIGSEGVが検出されたら、要求された(障害をスローした)メモリへのポインタと要求されたセグメントのサイズに何らかの方法でアクセスする必要があります。これは可能ですか?

void fifoSigHandler(){

    // Needs to only remove protection from requested block of virtual memory
    mprotect(fifoVm,(size_t)fifoVm_size,PROT_WRITE);
    printf("Caught Seg Fault");
}

void fifo_init(void* vm, int vm_size, int n_frames, int page_size)
{
    fifoVm = vm;
    fifoVm_size = vm_size;
    fifoFrames = n_frames;
    fifoPageSize = page_size;

    mprotect(fifoVm,(size_t)fifoVm_size,PROT_NONE);

    signal(SIGSEGV, fifoSigHandler);
}

さらに、メモリのブロックが現在割り当てられているmprotect()のレベル(PROT_NONE、PROT_READなど)を判別する方法はありますか?

4

3 に答える 3

6

sigactionハンドラーを確立するSA_SIGINFO代わりにを使用する必要があります。そうすると、を含むsignal有用な情報でコールバックされます。siginfo_tsi_addr

si_addrsigaction、 (2)で説明したように、アドレスが含まれます。長さに関しては、まあ、あなたが命令を解析する気がない限り、あなたは運が悪いです。で報告されたページに対してアクションを実行するのが最善の方法ですsi_addr。それでも不十分な場合は、すぐに別のシグナルを受け取ります。少なくとも、それがObjectStoreでのやり方です。

于 2010-04-24T19:13:20.470 に答える
1

あなたはhttp://libsigsegv.sourceforge.net/を探していますlibsigsegv

ただし、呼び出しはLinuxでのみシグナルセーフであることに注意してくださいmprotect。他のPOSIXシステムは、これをサポートしていない可能性があります。

Linuxでは、メモリ保護ビットを取得する唯一の方法は、読み込みを行うことです。/proc/$pid/meminfo

補足(Linuxのみ):メモリ消費が心配で、より大きなマッピングのページを1つずつ有効にする場合は、を使用mmapしてマッピングを作成することをお勧めします。MAP_NORESERVEこの場合、ゼロで埋められたマッピングが取得されます。最初の書き込み時に物理RAMを割り当てるコピーオンライトページ。MAP_NORESERVE最大64TBの仮想アドレス空間を割り当てることができるスワップスペースでメモリをバックアップしないようにカーネルに指示します。唯一の欠点は、メモリが不足すると、ひどいことが起こる可能性があることです(oom-killer)。

于 2012-09-27T19:12:21.097 に答える
1

ステップ1:初期化sigaction

struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;

ステップ2:このsigactionハンドルを作成しSIGSEGVます:

sigaction(SIGSEGV, &act, NULL);

(オプション)ステップ3:他のメモリ信号も処理するようにします。

sigaction(SIGBUS, &act, NULL);
sigaction(SIGTRAP, &act, NULL);

必要に応じてエラー処理を追加します

ステップ4:ハンドラー関数を定義します。

void handler(int signal, siginfo_t* siginfo, void* uap) {
    printf("Attempt to access memory at address %p\n", 
           siginfo->si_addr);
    #ifdef LINUX_64BIT
    printf("Instruction pointer: %p\n",
           (((ucontext_t*)uap)->uc_mcontext.gregs[16]));
    #elif LINUX_32BIT
    printf("Instruction pointer: %p\n",
           (((ucontext_t*)uap)->uc_mcontext.gregs[14]));
    #endif
}

ハンドラーが抽出できるより興味深いデータについては、マニュアルページを参照してucontext_tください。siginfo_t

于 2016-09-29T04:03:36.243 に答える