Dydaktyka
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Ćwiczenia 2, grupa cz. 10-12, 20 października 2022 ###### tags: `SO22` `ćwiczenia` `pwit` ## Deklaracje Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle. **UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!** :::danger | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | ----------------------:| ----- | --- | --- | --- | --- | --- | --- | --- | Miriam Bouhajeb | X | | X | X | X | | | | Kacper Chmielewski | X | X | X | X |==X==| X | | | Jan Jankowicz | | | | | | | | | Jakub Kaczmarek | | | | | | | | | Jarosław Kadecki | X | | X | X | X | X | | | Zuzanna Kania | X | | X | | X | | | | Julia Konefał | | | X | X | | | | | Daniel Sarniak | X | X | X | X | | X | X | X | Paweł Tkocz | X | | X | X | | | | | Miłosz Urbanik | X | | X | X | X | X | | X | Tomasz Wołczański | X | | X | X | X | X | X | X | Radosław Śliwiński | X | | X | X | | | | | ::: :::info **Uwaga:** Po rozwiązaniu zadania należy zmienić kolor nagłówka na zielony. ::: ## Zadanie 1 :::success Autor: Miłosz Urbanik ![](https://i.imgur.com/PUrOu5T.png) ::: ![](https://i.imgur.com/mpjVAuE.png) Stany 1. Stopped - zatrzymany sygnałem `SIGSTOP` lub `SIGTSTP`. Proces nie wykonuje się, ani nie odbiera sygnałów(z wyjątkiem `SIGKILL`) do momentu otrzymania sygnału `SIGCONT` 2. Running 2.1. Ready - proces załadowany do pamięci, czeka na przydzielenie czasu CPU przez scheduler 2.2 Executing - proces wykonywany przez CPU 3. Zombie - proces zakończony, ale nie pogrzebany 4. Sleep 4.1 Uninterruptible - proces jest zablokowany i nie reaguje na sygnały, tylko na dostęp do zasobów sprzętowych. Czeka do momentu zakończenia wywołania systemowego - najczęściej dostępu do dysku np. `mkdir` 4.2 Interruptible - proces zablokowany podobnie jak uninterruptible, ale odbiera sygnały * ignorowanie sygnału - ustawienie `sigaction` na `SIG_IGN`, po odebraniu sygnału proces wraca do wykonywanej instrukcji, nie obsługuje sygnału. * blokowanie sygnału - dodanie sygnału do maski blokowanych sygnałów. Jądro nie przekazuje sygnału do procesu, zaznacza tylko sygnał jako `pending` w masce oczekujących sygnałów. Sygnał jest przekazywany do procesu dopiero po odblokowaniu odpowiedniego sygnału. Za manualem: `The signals SIGKILL and SIGSTOP cannot be caught or ignored.` Zablokowanie SIGKILL zostanie "po cichu" zignorowane. SIGSEGV można zarówno blokować, jak i ignorować. `According to POSIX, the behavior of a process is undefined after it ignores a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(2) or raise(3)` Jeśli zignorujemy SIGSEGV w programie z błędnym dostępem do pamięci, to po "zignorowaniu" sygnału wracamy do instrukcji, która ponownie spowoduje SIGSEGV. ```c= #include "include/csapp.h" #include <bits/types/sig_atomic_t.h> int main(){ printf("my pid is %d\n", getpid()); signal(SIGSEGV, SIG_IGN); printf("SIGSEGV ignored\n"); sleep(20); //tutaj kill -SIGSEGV [pid] nie powoduje zatrzymania procesu printf("sleep finished\n"); signal(SIGSEGV, SIG_DFL); sigset_t block_segv, waiting_mask; sigemptyset(&block_segv); sigaddset(&block_segv, SIGSEGV); sigprocmask(SIG_SETMASK, &block_segv, NULL); printf("SIGSEGV blocked\n"); sleep(20); // kill -SIGSEGV [pid] nie zatrzymuje procesu sigpending(&waiting_mask); //sigpending sprawdza sygnały oczekujące if(sigismember(&waiting_mask, SIGSEGV)) //jeśli wysłaliśmy sygnał to jest to członkiem maski pending printf("SIGSEGV pending\n"); else printf("SIGSEGV lost\n"); } ``` ## Zadanie 2 :::success Autor: Daniel Sarniak ![](https://i.imgur.com/sQpPauv.png) **Tworzenie procesów w systemie:** **Linux:** * Zostaje utworzony nowy deskryptor procesu (`task_struct` - struktura przechowująca wszystkie informacje o danym procesie) i obszar użytkownia dla procesu potomnego. Większość danych zostaje przepisana od rodzica. * Dziecko dostaje swój identyfikator PID * Proces potomny otrzymuje mapę pamięci i współdzielony dostęp do plików swojego rodzica * Rejestry zostają usawione i proces staje się gotowy do wykonania. **WinNT:** Tutaj procesy tworzy się w inny sposób niż w Linuxie. Zamiast wywołania `fork()` używane jest wywołanie `CreateProcess`, tworzące zupełnie nowy proces, a nie klon procesu jak w Linuxie. `CreateProcess` wykonuje program podany mu jako argument. Stworzony proces nie otrzymuje kopii pamięci swojego rodzica `CreateProcess` można w pewien sposób porównać do połączenia `fork` z `execve`. Grafika z podanej literatury przedstawiająca przebieg tworzenia nowego procesu przy pomocy `fork()` + `exec()` ![](https://i.imgur.com/5CFZmhQ.png) * Kiedy `fork` zostaje wywołany, kernel tworzy `task_struct` i struktury danych takie jak `kernel-mode stack` czy `thread_info`. Nowa struktrua zadania, umieszczana jest w pamięci na pozycji przesuniętej o daną stałą wartość względem końca stosu danego procesu, reprezentuje szereg parametrów procesu, w tym adres jego deskryptora. Znaczna większość zawartości deksryptora jest kopiowana z procesu rodzica. Następnie szuka się wolnego identyfikatora PID i uaktualnia tablicę haszującą tak, żeby PID wskazywało na naszego nowego `task_structa`. Na koniec kopiuje się pamięć rodzica. Choć nie jest to do końca trafne stwierdznie. Pamięć powina być kopiowana z definicji `fork`, lecz jest to bardzo kosztowna operacja. Nowoczesne Linuxy stosują więc pewne oszustwo. Dają procesowi potomnemu własną tablice stron, która wskazuje na strony rodzica (ale w trybie read-only). Jeżeli dowolny z procesów (dziecko/rodzic) będzie chicało zapisać na tej stronie otrzyma `protection foult`. Kernel widząć to alokuje nową kopie strony do tego procesu jako read/write, dzięki czemu tylko strony faktycznie używane do zapisu będą kopiowane. Mechanizm ten nazywa się copy on write. * Wywołanie `exec` sprawia, że jądro zaczyna od szukania programu wykonywalnego, następnie sprawdza uprawnienia wykonywania, po czym kopiuje argumenty i środowisko oraz zwalnia starą przestrzeń adresową, i tablicę stron. Tworzona zostaje nowa przestrzeń adresowa ale nie zostaje ona uzupełniona. Start procesu skutkuje `page fault`, który sprawia, że pierwsza strona kodu zostaje wprowadzona z pliku wykonywalnego. Dzięki temu, nie musimy ładować danych z wyprzedzeniem, przez co programy mogą uruchamiać się szybko. Na koniec argumenty i zmienne środowiskowe zostają skopiowane na stos, sygnały zostają zresetowane a rejestry wypełnione zerami. ![](https://i.imgur.com/O0H5cme.png) Jak widać, wywołanie naraz połączonego wywołania `fork()`+`execve()` jako `spawn()` pozbawia nas mozliwości wprowadzania zmian pomiędzy wywołaniami `fork` i `execve` co powoduje problemy np z potokami. Najłatwiej wytłumaczyć to właśnie na podstawie **potków**. Jeżeli chicelibyśmy użyć potoku pomiędzy dwiema komendami potrzebujemy dwóch deskryptorów plików, które chcemy odpowiednio przekierowywać na `stdin` i `stdout` potoku. Przykładowo, przed wykonaniem `execve()` musimy ustawić jego `stdin` na "reading end of pipe". Przykład implementacji `ls | less` znaleziony w internecie http://www.cse.cuhk.edu.hk/~ericlo/teaching/os/lab/6-IPC1/pipe-shell.html ```c /* pipe4.c */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> int main(int agrc, char* agrv[]) { int pipefds[2]; pid_t pid; if(pipe(pipefds) == -1){ perror("pipe"); exit(EXIT_FAILURE); } pid = fork(); if(pid == -1){ perror("fork"); exit(EXIT_FAILURE); } if(pid == 0){ //replace stdout with the write end of the pipe dup2(pipefds[1],STDOUT_FILENO); //close read to pipe, in child close(pipefds[0]); execlp("ls","ls",NULL); exit(EXIT_SUCCESS); }else{ //Replace stdin with the read end of the pipe dup2(pipefds[0],STDIN_FILENO); //close write to pipe, in parent close(pipefds[1]); execlp("less","less",NULL); exit(EXIT_SUCCESS); } } ``` Przykład potoków: często wykorzystywany na poprzedniej liście: `ps ax | grep X` **Przekierowanie** przekierowuje `stdout` procesu na początek pliku ::: ## Zadanie 3 :::success Autor: Julia Konefał ::: :::info Zadanie 3. Na podstawie dokumentacji fork(2) (§8.3) i execve(2) (§8.10) wymień najważniejsze zasoby procesu, które są (a) dziedziczone przez proces potomny (b) przekazywane do nowego programu załadowanego do przestrzeni adresowej. Czemu przed wywołaniem fork należy opróżnić bufory biblioteki stdio(3)? Co jądro robi w trakcie wywołania execve z konfiguracją zainstalowanych procedur obsługi sygnałów? ::: a) fork (tworzy proces potomny) przekazuje: * identyfikatory: real user/group ID, effective user/group ID, process group ID * ustawienia środowiska: USER, LOGNAME (nazwa użytkownika), HOME (katalog domowy) LANG (locale) PATH (prefiksy nazw plików, które programy przeszukują, kiedy szukają plików o niekompletnej nazwie) PWD (aktualna ścieżka) TERM (typ terminala, dla którego przygotowywany jest output) * aktualną ścieżkę, w której się znajduje * maska uprawnień pliku * terminal, który je kontroluje * signal handlers * dzielona pamięć * mapy pamięci * limit zasobów Przed jego wywołaniem należy opróżnić bufory stdio, ponieważ chcemy uniknąć kilkukrotnego wypisywania danych. b) execve (wywołuje nowy program) przekazuje: * identyfikatory: process -/parent/group ID, real user/group ID, supplementary groups IDs * deskryptory plików * dzielona pamięć * czas pozostały do alarm clock signal * aktualną ścieżkę * maskę sygnałów (zablokowane sygnały) * oczekujące sygnały * czasy egzekucji procesów * terminal, który go kontroluje **Zainstalowane** procedury obsugi sygnałów – procedury definiujące obsługę sygnałów SIGUSR1 i SIGUSR2. Jądro przywraca standardową obsługę tylko tych sygnałów, dla których użytkownik sam ustawił wcześniej nową procedurę obsługi. Oznacza to, ze sygnały, które były ignorowane w programie wywołującym, pozostaną takimi w programie wywoływanym. ## Zadanie 4 :::success Autor: Jarosław Kadecki ::: ![](https://i.imgur.com/3HAv4xS.png) Domyslnie wysłane sygnały: kill - służy do wysyłania sygnału do procesu sprecyzowanego PID'em. Domyślnie TERM pkill - służy do wysyłania sygnału do procesu sprecyzowanego nazwą. Domyślnie SIGTERM xkill - służy do zamykania polączenia procesu z serwerem X. Sygnały oczekujące - sygnały których dostarczenie jest wstrzymane do momentu wyjścia z nieprzerywalnego snu SigQ to pole zawierające dwie liczby które oznaczają liczbę zakolejkowanych sygnałów dla real user ID oraz limit zakolejkowanych sygnałów dla tego procesu. SigPnd, ShdPnd to pola z liczbą sygnałów oczekujących na wątek oraz na cały proces. SigBlk, SigIgn, SigCgt to maski sygnałów blokowanych, ignorowanych oraz złapanych. Sygnały oczekujące - sygnały których dostarczenie jest wstrzymane do momentu wyjścia z nieprzerywalnego snu Wysyłane sygnały: SIGUSR1 - 10 SIGUSR2 - 12 SIGHUP - 1 - Hangup detected on controlling terminal or death of controlling process SIGINIT - 2 nasłuchujemy jakie sygnały dochodzą do xeyes przy użyciu: strace -e trace=signal -p PID Zatrzymujemy xeyes wysyłamy sygnały: kill -10 PID kill -12 PID kill -1 PID kill -2 PID Wznawiamy proces kill -18 PID Sprawdzamy na strac'e, że SIGHUP jest pierwszym obsługiwanym sygnałem. ## Zadanie 5 :::success Autor: Kacper Chmielewski ![](https://i.imgur.com/eWOlmgT.png) Jakie zadanie pełni minimalny program rozruchowy? - wchodzi do roota, - przygotowywuje tablice sygnałów tak aby wszystkie sygnał← z POSIX.1-2017 były zawarte, - wywołuje funkcje init, - po czym czuwa czy są wysyłane sygnały zawarte w sigmap. Możemy więc zauważyć, że ten program po wywołaniu 'init', co jakiś czas sprawdza czy należy rozpatrzeć jakiś sygnał z tablicy sigmap. Jakie akcje wykonuje pod wpływem wysyłania do niego sygnałów wymienionych w tablicy «sigmap»? Wywołuje funkcję (która jest przechowywana pod wskaźnikiem w sigmapie), obsługi danego sygnału. Do czego służą procedury sigprocmask(2) i sigwait(3)? Sigprocmask rozpatruje i zmnienia blockowane sygnały. / jest używany do dodania lub zmieniea sygnały maski dla wywołującego ją wątku. Maska sygnału jest zbiorem sygnałów które dostarczenie jest obecnie zblokowane przez callera. Sigwait jest funckją, która zawiesza wykonanie wywołanego wątku, aż dostanie sygnał "set". W jaki sposób grzebie swoje dzieci? Zaa pomocą funckji sigreap, w której jest wywoływana funkcja waitpid. ```=C /* See LICENSE file for copyright and license details. */ #include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define LEN(x) (sizeof (x) / sizeof *(x)) #define TIMEO 30 static void sigpoweroff(void); static void sigreap(void); static void sigreboot(void); static void spawn(char *const []); static struct { int sig; void (*handler)(void); } sigmap[] = { { SIGUSR1, sigpoweroff }, { SIGCHLD, sigreap }, { SIGALRM, sigreap }, { SIGINT, sigreboot }, }; #include "config.h" static sigset_t set; int main(void){ int sig; size_t i; if (getpid() != 1) return 1; chdir("/"); sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); spawn(rcinitcmd); while (1) { alarm(TIMEO); sigwait(&set, &sig); for (i = 0; i < LEN(sigmap); i++) { if (sigmap[i].sig == sig) { sigmap[i].handler(); break; } } } /* not reachable */ return 0; } static void sigpoweroff(void){ spawn(rcpoweroffcmd); } static void sigreap(void) { while (waitpid(-1, NULL, WNOHANG) > 0); alarm(TIMEO); } static void sigreboot(void){ spawn(rcrebootcmd); } static void spawn(char *const argv[]){ switch (fork()) { case 0: sigprocmask(SIG_UNBLOCK, &set, NULL); setsid(); execvp(argv[0], argv); perror("execvp"); _exit(1); case -1: perror("fork"); } } ``` ::: ## Zadanie 6 :::success Autor: Tomasz Wołczański ::: ![](https://i.imgur.com/HbIdiP9.png) ```c #include "csapp.h" static pid_t spawn(void (*fn)(void)) { pid_t pid = Fork(); if (pid == 0) { fn(); printf("(%d) I'm done!\n", getpid()); exit(EXIT_SUCCESS); } return pid; } static void grandchild(void) { printf("(%d) Waiting for signal!\n", getpid()); pause(); printf("(%d) Got the signal!\n", getpid()); } static void child(void) { pid_t pid; setpgrp(); pid = spawn(grandchild); printf("(%d) Grandchild (%d) spawned!\n", getpid(), pid); } /* Runs command "ps -o pid,ppid,pgrp,stat,cmd" using execve(2). */ static void ps(void) { char *argv[] = {"ps", "-o", "pid,ppid,pgrp,stat,cmd", NULL}; execvp(argv[0], argv); } int main(void) { /* TODO: Make yourself a reaper. */ #ifdef LINUX Prctl(PR_SET_CHILD_SUBREAPER, 1); #endif printf("(%d) I'm a reaper now!\n", getpid()); pid_t pid, pgrp; int status; pid = spawn(child); pgrp = pid; printf("(%d) Child (%d) spawned!\n", getpid(), pid); waitpid(pid, &status, 0); printf("(%d) Child (%d) terminated with status %d\n", getpid(), pid, status); pid = spawn(ps); printf("(%d) ps (%d) spawned!\n", getpid(), pid); waitpid(pid, &status, 0); printf("(%d) ps (%d) terminated with status %d\n", getpid(), pid, status); kill(-pgrp, SIGINT); waitpid(-pgrp, &status, 0); printf("(%d) Grandchild (%d) killed - terminated with status %d\n", getpid(), pid, status); return EXIT_SUCCESS; } ``` ![](https://i.imgur.com/s57oLTI.png) ## Zadanie 7 :::success Autor: Tomasz Wołczański ::: ![](https://i.imgur.com/BfJKUND.png) ```c= #include "csapp.h" static void signal_handler(int signum, siginfo_t *info, void *data) { if (signum == SIGINT) { safe_printf("(%d) Screw you guys... I'm going home!\n", getpid()); _exit(0); } } static void play(pid_t next, const sigset_t *set) { for (;;) { printf("(%d) Waiting for a ball!\n", getpid()); /* TODO: Something is missing here! */ Sigsuspend(set); usleep((300 + random() % 400) * 1000); Kill(next, SIGUSR1); printf("(%d) Passing ball to (%d)!\n", getpid(), next); } } int main(int argc, char *argv[]) { if (argc != 2) app_error("Usage: %s [CHILDREN]", argv[0]); int children = atoi(argv[1]); if (children < 4 || children > 20) app_error("Give number of children in range from 4 to 20!"); /* Register signal handler for SIGUSR1 */ struct sigaction action = {.sa_sigaction = signal_handler}; Sigaction(SIGINT, &action, NULL); Sigaction(SIGUSR1, &action, NULL); /* TODO: Start all processes and make them wait for the ball! */ sigset_t mask, prev_mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); Sigprocmask(SIG_BLOCK, &mask, &prev_mask); pid_t next = getpid(); for(int i = 0; i < children; i++) { pid_t pid = Fork(); if(pid == 0) { play(next, &prev_mask); } printf("(%d) Child (%d) created!\n", getpid(), pid); next = pid; } Kill(next, SIGUSR1); play(next, &prev_mask); return EXIT_SUCCESS; } } ``` Piłki mogą skleić się w jedną. Wystarczy, że jeden proces otrzyma dwie piłki przed tym, jak zostanie wybudzony z `sigsuspend`. ## Zadanie 8 :::success Autor: Miłosz Urbanik![](https://i.imgur.com/WuUgfE5.png) ::: * procedura obsługi sygnału - procedura przypisana do odpowiedniego sygnału funkcją `int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);` przez strukturę `sigaction`. Wywołana po otrzymaniu sygnału. * strona wirtualna - ciągły blok pamięci wirtualnej, mapowany do stron pamięci rzeczywistej * błąd strony - przerwanie spowodowane próbą dostępu do pamięci, która nie została wczytana do RAM * pamięć wirtualna - abstrakcja pamięci dostępnej dla procesu * procedury wielobieżne (reentrant functions, async-signal safe) - funkcje, które mogą być bezpiecznie zatrzymywane i wielokrotnie uruchamiane z różnych wątków. Charaketryzują się tym, że nie korzystają ze zmiennych globalnych, ani lokalnych zmiennych statycznych, wszystkie wywołane przez nie funkcje też są wielobieżne. Z manuala `sigaction` struktura zawierająca informacje o sygnale ```c= siginfo_t { int si_signo; /* Signal number */ int si_errno; /* An errno value */ int si_code; /* Signal code */ int si_trapno; /* Trap number that caused hardware-generated signal (unused on most architectures) */ pid_t si_pid; /* Sending process ID */ uid_t si_uid; /* Real user ID of sending process */ int si_status; /* Exit value or signal */ clock_t si_utime; /* User time consumed */ clock_t si_stime; /* System time consumed */ union sigval si_value; /* Signal value */ int si_int; /* POSIX.1b signal */ void *si_ptr; /* POSIX.1b signal */ int si_overrun; /* Timer overrun count; POSIX.1b timers */ int si_timerid; /* Timer ID; POSIX.1b timers */ void *si_addr; /* Memory location which caused fault */ long si_band; /* Band event (was int in glibc 2.3.2 and earlier) */ int si_fd; /* File descriptor */ short si_addr_lsb; /* Least significant bit of address (since Linux 2.6.32) */ void *si_lower; /* Lower bound when address violation occurred (since Linux 3.19) */ void *si_upper; /* Upper bound when address violation occurred (since Linux 3.19) */ int si_pkey; /* Protection key on PTE that caused fault (since Linux 4.6) */ void *si_call_addr; /* Address of system call instruction (since Linux 3.5) */ int si_syscall; /* Number of attempted system call (since Linux 3.5) */ unsigned int si_arch; /* Architecture of attempted system call (since Linux 3.5) */ } ``` Manual `getcontext` ```c= typedef struct ucontext_t { struct ucontext_t *uc_link; sigset_t uc_sigmask; stack_t uc_stack; mcontext_t uc_mcontext; ... } ucontext_t; ``` Z `/usr/lib/x86_64-linux-gnu/sys/ucontext.h` ```c= /* Context to describe whole processor state. */ typedef struct { gregset_t __ctx(gregs); /* Note that fpregs is a pointer. */ fpregset_t __ctx(fpregs); __extension__ unsigned long long __reserved1 [8]; } mcontext_t; /* Userlevel context. */ typedef struct ucontext_t { unsigned long int __ctx(uc_flags); struct ucontext_t *uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; struct _libc_fpstate __fpregs_mem; __extension__ unsigned long long int __ssp[4]; } ucontext_t; ``` Kod zmodyfikowanego handlera sygnału SIGSEGV ```c= static void sigsegv_handler(int signum, siginfo_t *info, void *data) { ucontext_t *uc = data; intptr_t rip; /* TODO: You need to get value of instruction pointer register from `uc`. * Print all useful data from `info` and quit in such a way that a shell * reports program has been terminated with SIGSEGV. */ rip = uc->uc_mcontext.gregs[17]; //enum w ucontext.h RIP_REG, gregs to tablica General REGisterS /* * SIGILL, SIGFPE, SIGSEGV, SIGBUS, and SIGTRAP fill in si_addr with the address of the fault. On some architectures, these signals also fill in the si_trapno field. */ void* accs_addr = info->si_addr; int err_code = info->si_code; if(accs_addr > ADDR_START && accs_addr < ADDR_END) { void* page_addr = (void*)((long)accs_addr - ((long)accs_addr % pagesize)); if(err_code == SEGV_MAPERR) { safe_printf("Fault at rip=%lx accessing %lx! Map missing page at %lx.\n", (long)rip, (long)accs_addr, (long)page_addr); mmap_page(page_addr, PROT_WRITE); } else if(err_code == SEGV_ACCERR) { safe_printf("Fault at rip=%lx accessing %lx! Make page at %lx writable.\n", (long)rip, (long)accs_addr, (long)page_addr); mprotect_page(page_addr, PROT_WRITE); } } else { safe_printf("Fault at rip=%lx accessing %lx! Address not mapped - terminating!\n", (long)rip, (long)accs_addr); exit(139); } } ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully