C SIGSEGV Handler & mprotect
Frage
Ich bin den Aufbau eines Programms, das mprotect () verwendet, um einen Block von Speicher zu beschränken den Zugriff. Wenn der Speicher angefordert wird, wird ein SIGSEGV geworfen, die ich für die Verwendung eines Signals () mithören.
Sobald die SIGSEGV erkannt wurden, muß ich den Zeiger auf den Speicher irgendwie zuzugreifen, die angefordert wurde (das wirft er den Fehler) und die Größe des Segments angefordert. Ist das möglich?
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);
}
Darüber hinaus ist es eine Möglichkeit, die Höhe der mprotect () ein Speicherblock zu bestimmen aktuell zugeordnet ist (PROT_NONE, PROT_READ, etc ..)?
Lösung
Sie haben sigaction
mit SA_SIGINFO
zu verwenden, anstatt signal
Handler zu etablieren, und dann werden Sie wieder mit nützlichen Informationen in einem siginfo_t
aufgerufen, darunter si_addr
.
si_addr
, erklärt wie in sigaction
(2), wird die Adresse enthalten. Was die Länge, gut, du bist kein Glück, wenn Sie bereit sind, Anweisungen zu analysieren. Beste, was Sie tun können, ist take action für die Seite in si_addr
berichtet, und dann, wenn das nicht genug ist, werden Sie ein anderes Signal schnell genug bekommen. Zumindest das ist, wie wir haben die Dinge in Objektspeicher.
Andere Tipps
Sie suchen libsigsegv
http://libsigsegv.sourceforge.net/
Aber Vorsicht, dass mprotect
Aufruf ist nur Signal sicher in Linux, anderen POSIX-Systeme können dies nicht unterstützen.
Ich fürchte, dass in Linux die einzige Möglichkeit, Speicherschutz-Bits zu erhalten, ist in /proc/$pid/meminfo
lesen
Auf einer seitlichen Anmerkung (nur Linux): Wenn Sie über den Speicherverbrauch besorgt und beabsichtigen Seiten einer größeren Abbildung eines aktivieren, indem man dann würde ich Ihre Mapping mmap
mit MAP_NORESERVE
in diesem Fall raten erstellen Sie eine bekommen Mapping auf Null gefüllten copy-on-write-Seiten, die physikalische RAM auf dem ersten Schreib zuteilen wird. MAP_NORESERVE
weist den Kernel nicht Ihr Gedächtnis mit Swap-Speicher sichern so dass Sie 64 TB virtuellen Adressraum zuweisen oben. Einziger Nachteil ist, dass, wenn Sie genügend Speicherplatz sichern! Schreckliche Dinge passieren können (OOM-Killer).
Schritt 1: : Init ein 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;
Schritt 2 : Nehmen Sie diese sigaction
Griff SIGSEGV
:
sigaction(SIGSEGV, &act, NULL);
(Optional) Schritt 3: : Machen Sie es andere Speichersignale verarbeiten zu:
sigaction(SIGBUS, &act, NULL);
sigaction(SIGTRAP, &act, NULL);
Fügen Sie Fehlerbehandlung als notwendig
Schritt 4: : Definieren Sie die Handler-Funktion:
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
}
Sie können beziehen sich auf die man-Seiten für ucontext_t
und siginfo_t
für interessantere Daten Handler extrahieren können.