xref: /openbmc/qemu/util/oslib-posix.c (revision 8e6fe6b8)
1 /*
2  * os-posix-lib.c
3  *
4  * Copyright (c) 2003-2008 Fabrice Bellard
5  * Copyright (c) 2010 Red Hat, Inc.
6  *
7  * QEMU library functions on POSIX which are shared between QEMU and
8  * the QEMU tools.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28 
29 #include "qemu/osdep.h"
30 #include <termios.h>
31 
32 #include <glib/gprintf.h>
33 
34 #include "qemu-common.h"
35 #include "sysemu/sysemu.h"
36 #include "trace.h"
37 #include "qapi/error.h"
38 #include "qemu/sockets.h"
39 #include <libgen.h>
40 #include <sys/signal.h>
41 #include "qemu/cutils.h"
42 
43 #ifdef CONFIG_LINUX
44 #include <sys/syscall.h>
45 #endif
46 
47 #ifdef __FreeBSD__
48 #include <sys/sysctl.h>
49 #include <sys/user.h>
50 #include <libutil.h>
51 #endif
52 
53 #ifdef __NetBSD__
54 #include <sys/sysctl.h>
55 #endif
56 
57 #include "qemu/mmap-alloc.h"
58 
59 #ifdef CONFIG_DEBUG_STACK_USAGE
60 #include "qemu/error-report.h"
61 #endif
62 
63 #define MAX_MEM_PREALLOC_THREAD_COUNT 16
64 
65 struct MemsetThread {
66     char *addr;
67     size_t numpages;
68     size_t hpagesize;
69     QemuThread pgthread;
70     sigjmp_buf env;
71 };
72 typedef struct MemsetThread MemsetThread;
73 
74 static MemsetThread *memset_thread;
75 static int memset_num_threads;
76 static bool memset_thread_failed;
77 
78 int qemu_get_thread_id(void)
79 {
80 #if defined(__linux__)
81     return syscall(SYS_gettid);
82 #else
83     return getpid();
84 #endif
85 }
86 
87 int qemu_daemon(int nochdir, int noclose)
88 {
89     return daemon(nochdir, noclose);
90 }
91 
92 bool qemu_write_pidfile(const char *path, Error **errp)
93 {
94     int fd;
95     char pidstr[32];
96 
97     while (1) {
98         struct stat a, b;
99         struct flock lock = {
100             .l_type = F_WRLCK,
101             .l_whence = SEEK_SET,
102             .l_len = 0,
103         };
104 
105         fd = qemu_open(path, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
106         if (fd == -1) {
107             error_setg_errno(errp, errno, "Cannot open pid file");
108             return false;
109         }
110 
111         if (fstat(fd, &b) < 0) {
112             error_setg_errno(errp, errno, "Cannot stat file");
113             goto fail_close;
114         }
115 
116         if (fcntl(fd, F_SETLK, &lock)) {
117             error_setg_errno(errp, errno, "Cannot lock pid file");
118             goto fail_close;
119         }
120 
121         /*
122          * Now make sure the path we locked is the same one that now
123          * exists on the filesystem.
124          */
125         if (stat(path, &a) < 0) {
126             /*
127              * PID file disappeared, someone else must be racing with
128              * us, so try again.
129              */
130             close(fd);
131             continue;
132         }
133 
134         if (a.st_ino == b.st_ino) {
135             break;
136         }
137 
138         /*
139          * PID file was recreated, someone else must be racing with
140          * us, so try again.
141          */
142         close(fd);
143     }
144 
145     if (ftruncate(fd, 0) < 0) {
146         error_setg_errno(errp, errno, "Failed to truncate pid file");
147         goto fail_unlink;
148     }
149 
150     snprintf(pidstr, sizeof(pidstr), FMT_pid "\n", getpid());
151     if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr)) {
152         error_setg(errp, "Failed to write pid file");
153         goto fail_unlink;
154     }
155 
156     return true;
157 
158 fail_unlink:
159     unlink(path);
160 fail_close:
161     close(fd);
162     return false;
163 }
164 
165 void *qemu_oom_check(void *ptr)
166 {
167     if (ptr == NULL) {
168         fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
169         abort();
170     }
171     return ptr;
172 }
173 
174 void *qemu_try_memalign(size_t alignment, size_t size)
175 {
176     void *ptr;
177 
178     if (alignment < sizeof(void*)) {
179         alignment = sizeof(void*);
180     }
181 
182 #if defined(CONFIG_POSIX_MEMALIGN)
183     int ret;
184     ret = posix_memalign(&ptr, alignment, size);
185     if (ret != 0) {
186         errno = ret;
187         ptr = NULL;
188     }
189 #elif defined(CONFIG_BSD)
190     ptr = valloc(size);
191 #else
192     ptr = memalign(alignment, size);
193 #endif
194     trace_qemu_memalign(alignment, size, ptr);
195     return ptr;
196 }
197 
198 void *qemu_memalign(size_t alignment, size_t size)
199 {
200     return qemu_oom_check(qemu_try_memalign(alignment, size));
201 }
202 
203 /* alloc shared memory pages */
204 void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared)
205 {
206     size_t align = QEMU_VMALLOC_ALIGN;
207     void *ptr = qemu_ram_mmap(-1, size, align, shared, false);
208 
209     if (ptr == MAP_FAILED) {
210         return NULL;
211     }
212 
213     if (alignment) {
214         *alignment = align;
215     }
216 
217     trace_qemu_anon_ram_alloc(size, ptr);
218     return ptr;
219 }
220 
221 void qemu_vfree(void *ptr)
222 {
223     trace_qemu_vfree(ptr);
224     free(ptr);
225 }
226 
227 void qemu_anon_ram_free(void *ptr, size_t size)
228 {
229     trace_qemu_anon_ram_free(ptr, size);
230     qemu_ram_munmap(-1, ptr, size);
231 }
232 
233 void qemu_set_block(int fd)
234 {
235     int f;
236     f = fcntl(fd, F_GETFL);
237     assert(f != -1);
238     f = fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
239     assert(f != -1);
240 }
241 
242 void qemu_set_nonblock(int fd)
243 {
244     int f;
245     f = fcntl(fd, F_GETFL);
246     assert(f != -1);
247     f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
248 #ifdef __OpenBSD__
249     if (f == -1) {
250         /*
251          * Previous to OpenBSD 6.3, fcntl(F_SETFL) is not permitted on
252          * memory devices and sets errno to ENODEV.
253          * It's OK if we fail to set O_NONBLOCK on devices like /dev/null,
254          * because they will never block anyway.
255          */
256         assert(errno == ENODEV);
257     }
258 #else
259     assert(f != -1);
260 #endif
261 }
262 
263 int socket_set_fast_reuse(int fd)
264 {
265     int val = 1, ret;
266 
267     ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
268                      (const char *)&val, sizeof(val));
269 
270     assert(ret == 0);
271 
272     return ret;
273 }
274 
275 void qemu_set_cloexec(int fd)
276 {
277     int f;
278     f = fcntl(fd, F_GETFD);
279     assert(f != -1);
280     f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
281     assert(f != -1);
282 }
283 
284 /*
285  * Creates a pipe with FD_CLOEXEC set on both file descriptors
286  */
287 int qemu_pipe(int pipefd[2])
288 {
289     int ret;
290 
291 #ifdef CONFIG_PIPE2
292     ret = pipe2(pipefd, O_CLOEXEC);
293     if (ret != -1 || errno != ENOSYS) {
294         return ret;
295     }
296 #endif
297     ret = pipe(pipefd);
298     if (ret == 0) {
299         qemu_set_cloexec(pipefd[0]);
300         qemu_set_cloexec(pipefd[1]);
301     }
302 
303     return ret;
304 }
305 
306 char *
307 qemu_get_local_state_pathname(const char *relative_pathname)
308 {
309     return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR,
310                            relative_pathname);
311 }
312 
313 void qemu_set_tty_echo(int fd, bool echo)
314 {
315     struct termios tty;
316 
317     tcgetattr(fd, &tty);
318 
319     if (echo) {
320         tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
321     } else {
322         tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
323     }
324 
325     tcsetattr(fd, TCSANOW, &tty);
326 }
327 
328 static char exec_dir[PATH_MAX];
329 
330 void qemu_init_exec_dir(const char *argv0)
331 {
332     char *dir;
333     char *p = NULL;
334     char buf[PATH_MAX];
335 
336     assert(!exec_dir[0]);
337 
338 #if defined(__linux__)
339     {
340         int len;
341         len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
342         if (len > 0) {
343             buf[len] = 0;
344             p = buf;
345         }
346     }
347 #elif defined(__FreeBSD__) \
348       || (defined(__NetBSD__) && defined(KERN_PROC_PATHNAME))
349     {
350 #if defined(__FreeBSD__)
351         static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
352 #else
353         static int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
354 #endif
355         size_t len = sizeof(buf) - 1;
356 
357         *buf = '\0';
358         if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
359             *buf) {
360             buf[sizeof(buf) - 1] = '\0';
361             p = buf;
362         }
363     }
364 #endif
365     /* If we don't have any way of figuring out the actual executable
366        location then try argv[0].  */
367     if (!p) {
368         if (!argv0) {
369             return;
370         }
371         p = realpath(argv0, buf);
372         if (!p) {
373             return;
374         }
375     }
376     dir = g_path_get_dirname(p);
377 
378     pstrcpy(exec_dir, sizeof(exec_dir), dir);
379 
380     g_free(dir);
381 }
382 
383 char *qemu_get_exec_dir(void)
384 {
385     return g_strdup(exec_dir);
386 }
387 
388 static void sigbus_handler(int signal)
389 {
390     int i;
391     if (memset_thread) {
392         for (i = 0; i < memset_num_threads; i++) {
393             if (qemu_thread_is_self(&memset_thread[i].pgthread)) {
394                 siglongjmp(memset_thread[i].env, 1);
395             }
396         }
397     }
398 }
399 
400 static void *do_touch_pages(void *arg)
401 {
402     MemsetThread *memset_args = (MemsetThread *)arg;
403     sigset_t set, oldset;
404 
405     /* unblock SIGBUS */
406     sigemptyset(&set);
407     sigaddset(&set, SIGBUS);
408     pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
409 
410     if (sigsetjmp(memset_args->env, 1)) {
411         memset_thread_failed = true;
412     } else {
413         char *addr = memset_args->addr;
414         size_t numpages = memset_args->numpages;
415         size_t hpagesize = memset_args->hpagesize;
416         size_t i;
417         for (i = 0; i < numpages; i++) {
418             /*
419              * Read & write back the same value, so we don't
420              * corrupt existing user/app data that might be
421              * stored.
422              *
423              * 'volatile' to stop compiler optimizing this away
424              * to a no-op
425              *
426              * TODO: get a better solution from kernel so we
427              * don't need to write at all so we don't cause
428              * wear on the storage backing the region...
429              */
430             *(volatile char *)addr = *addr;
431             addr += hpagesize;
432         }
433     }
434     pthread_sigmask(SIG_SETMASK, &oldset, NULL);
435     return NULL;
436 }
437 
438 static inline int get_memset_num_threads(int smp_cpus)
439 {
440     long host_procs = sysconf(_SC_NPROCESSORS_ONLN);
441     int ret = 1;
442 
443     if (host_procs > 0) {
444         ret = MIN(MIN(host_procs, MAX_MEM_PREALLOC_THREAD_COUNT), smp_cpus);
445     }
446     /* In case sysconf() fails, we fall back to single threaded */
447     return ret;
448 }
449 
450 static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages,
451                             int smp_cpus)
452 {
453     size_t numpages_per_thread;
454     size_t size_per_thread;
455     char *addr = area;
456     int i = 0;
457 
458     memset_thread_failed = false;
459     memset_num_threads = get_memset_num_threads(smp_cpus);
460     memset_thread = g_new0(MemsetThread, memset_num_threads);
461     numpages_per_thread = (numpages / memset_num_threads);
462     size_per_thread = (hpagesize * numpages_per_thread);
463     for (i = 0; i < memset_num_threads; i++) {
464         memset_thread[i].addr = addr;
465         memset_thread[i].numpages = (i == (memset_num_threads - 1)) ?
466                                     numpages : numpages_per_thread;
467         memset_thread[i].hpagesize = hpagesize;
468         qemu_thread_create(&memset_thread[i].pgthread, "touch_pages",
469                            do_touch_pages, &memset_thread[i],
470                            QEMU_THREAD_JOINABLE);
471         addr += size_per_thread;
472         numpages -= numpages_per_thread;
473     }
474     for (i = 0; i < memset_num_threads; i++) {
475         qemu_thread_join(&memset_thread[i].pgthread);
476     }
477     g_free(memset_thread);
478     memset_thread = NULL;
479 
480     return memset_thread_failed;
481 }
482 
483 void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
484                      Error **errp)
485 {
486     int ret;
487     struct sigaction act, oldact;
488     size_t hpagesize = qemu_fd_getpagesize(fd);
489     size_t numpages = DIV_ROUND_UP(memory, hpagesize);
490 
491     memset(&act, 0, sizeof(act));
492     act.sa_handler = &sigbus_handler;
493     act.sa_flags = 0;
494 
495     ret = sigaction(SIGBUS, &act, &oldact);
496     if (ret) {
497         error_setg_errno(errp, errno,
498             "os_mem_prealloc: failed to install signal handler");
499         return;
500     }
501 
502     /* touch pages simultaneously */
503     if (touch_all_pages(area, hpagesize, numpages, smp_cpus)) {
504         error_setg(errp, "os_mem_prealloc: Insufficient free host memory "
505             "pages available to allocate guest RAM");
506     }
507 
508     ret = sigaction(SIGBUS, &oldact, NULL);
509     if (ret) {
510         /* Terminate QEMU since it can't recover from error */
511         perror("os_mem_prealloc: failed to reinstall signal handler");
512         exit(1);
513     }
514 }
515 
516 uint64_t qemu_get_pmem_size(const char *filename, Error **errp)
517 {
518     struct stat st;
519 
520     if (stat(filename, &st) < 0) {
521         error_setg(errp, "unable to stat pmem file \"%s\"", filename);
522         return 0;
523     }
524 
525 #if defined(__linux__)
526     /* Special handling for devdax character devices */
527     if (S_ISCHR(st.st_mode)) {
528         char *subsystem_path = NULL;
529         char *subsystem = NULL;
530         char *size_path = NULL;
531         char *size_str = NULL;
532         uint64_t ret = 0;
533 
534         subsystem_path = g_strdup_printf("/sys/dev/char/%d:%d/subsystem",
535                                          major(st.st_rdev), minor(st.st_rdev));
536         subsystem = g_file_read_link(subsystem_path, NULL);
537         if (!subsystem) {
538             error_setg(errp, "unable to read subsystem for pmem file \"%s\"",
539                        filename);
540             goto devdax_err;
541         }
542 
543         if (!g_str_has_suffix(subsystem, "/dax")) {
544             error_setg(errp, "pmem file \"%s\" is not a dax device", filename);
545             goto devdax_err;
546         }
547 
548         size_path = g_strdup_printf("/sys/dev/char/%d:%d/size",
549                                     major(st.st_rdev), minor(st.st_rdev));
550         if (!g_file_get_contents(size_path, &size_str, NULL, NULL)) {
551             error_setg(errp, "unable to read size for pmem file \"%s\"",
552                        size_path);
553             goto devdax_err;
554         }
555 
556         ret = g_ascii_strtoull(size_str, NULL, 0);
557 
558 devdax_err:
559         g_free(size_str);
560         g_free(size_path);
561         g_free(subsystem);
562         g_free(subsystem_path);
563         return ret;
564     }
565 #endif /* defined(__linux__) */
566 
567     return st.st_size;
568 }
569 
570 char *qemu_get_pid_name(pid_t pid)
571 {
572     char *name = NULL;
573 
574 #if defined(__FreeBSD__)
575     /* BSDs don't have /proc, but they provide a nice substitute */
576     struct kinfo_proc *proc = kinfo_getproc(pid);
577 
578     if (proc) {
579         name = g_strdup(proc->ki_comm);
580         free(proc);
581     }
582 #else
583     /* Assume a system with reasonable procfs */
584     char *pid_path;
585     size_t len;
586 
587     pid_path = g_strdup_printf("/proc/%d/cmdline", pid);
588     g_file_get_contents(pid_path, &name, &len, NULL);
589     g_free(pid_path);
590 #endif
591 
592     return name;
593 }
594 
595 
596 pid_t qemu_fork(Error **errp)
597 {
598     sigset_t oldmask, newmask;
599     struct sigaction sig_action;
600     int saved_errno;
601     pid_t pid;
602 
603     /*
604      * Need to block signals now, so that child process can safely
605      * kill off caller's signal handlers without a race.
606      */
607     sigfillset(&newmask);
608     if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) {
609         error_setg_errno(errp, errno,
610                          "cannot block signals");
611         return -1;
612     }
613 
614     pid = fork();
615     saved_errno = errno;
616 
617     if (pid < 0) {
618         /* attempt to restore signal mask, but ignore failure, to
619          * avoid obscuring the fork failure */
620         (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
621         error_setg_errno(errp, saved_errno,
622                          "cannot fork child process");
623         errno = saved_errno;
624         return -1;
625     } else if (pid) {
626         /* parent process */
627 
628         /* Restore our original signal mask now that the child is
629          * safely running. Only documented failures are EFAULT (not
630          * possible, since we are using just-grabbed mask) or EINVAL
631          * (not possible, since we are using correct arguments).  */
632         (void)pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
633     } else {
634         /* child process */
635         size_t i;
636 
637         /* Clear out all signal handlers from parent so nothing
638          * unexpected can happen in our child once we unblock
639          * signals */
640         sig_action.sa_handler = SIG_DFL;
641         sig_action.sa_flags = 0;
642         sigemptyset(&sig_action.sa_mask);
643 
644         for (i = 1; i < NSIG; i++) {
645             /* Only possible errors are EFAULT or EINVAL The former
646              * won't happen, the latter we expect, so no need to check
647              * return value */
648             (void)sigaction(i, &sig_action, NULL);
649         }
650 
651         /* Unmask all signals in child, since we've no idea what the
652          * caller's done with their signal mask and don't want to
653          * propagate that to children */
654         sigemptyset(&newmask);
655         if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) {
656             Error *local_err = NULL;
657             error_setg_errno(&local_err, errno,
658                              "cannot unblock signals");
659             error_report_err(local_err);
660             _exit(1);
661         }
662     }
663     return pid;
664 }
665 
666 void *qemu_alloc_stack(size_t *sz)
667 {
668     void *ptr, *guardpage;
669     int flags;
670 #ifdef CONFIG_DEBUG_STACK_USAGE
671     void *ptr2;
672 #endif
673     size_t pagesz = getpagesize();
674 #ifdef _SC_THREAD_STACK_MIN
675     /* avoid stacks smaller than _SC_THREAD_STACK_MIN */
676     long min_stack_sz = sysconf(_SC_THREAD_STACK_MIN);
677     *sz = MAX(MAX(min_stack_sz, 0), *sz);
678 #endif
679     /* adjust stack size to a multiple of the page size */
680     *sz = ROUND_UP(*sz, pagesz);
681     /* allocate one extra page for the guard page */
682     *sz += pagesz;
683 
684     flags = MAP_PRIVATE | MAP_ANONYMOUS;
685 #if defined(MAP_STACK) && defined(__OpenBSD__)
686     /* Only enable MAP_STACK on OpenBSD. Other OS's such as
687      * Linux/FreeBSD/NetBSD have a flag with the same name
688      * but have differing functionality. OpenBSD will SEGV
689      * if it spots execution with a stack pointer pointing
690      * at memory that was not allocated with MAP_STACK.
691      */
692     flags |= MAP_STACK;
693 #endif
694 
695     ptr = mmap(NULL, *sz, PROT_READ | PROT_WRITE, flags, -1, 0);
696     if (ptr == MAP_FAILED) {
697         perror("failed to allocate memory for stack");
698         abort();
699     }
700 
701 #if defined(HOST_IA64)
702     /* separate register stack */
703     guardpage = ptr + (((*sz - pagesz) / 2) & ~pagesz);
704 #elif defined(HOST_HPPA)
705     /* stack grows up */
706     guardpage = ptr + *sz - pagesz;
707 #else
708     /* stack grows down */
709     guardpage = ptr;
710 #endif
711     if (mprotect(guardpage, pagesz, PROT_NONE) != 0) {
712         perror("failed to set up stack guard page");
713         abort();
714     }
715 
716 #ifdef CONFIG_DEBUG_STACK_USAGE
717     for (ptr2 = ptr + pagesz; ptr2 < ptr + *sz; ptr2 += sizeof(uint32_t)) {
718         *(uint32_t *)ptr2 = 0xdeadbeaf;
719     }
720 #endif
721 
722     return ptr;
723 }
724 
725 #ifdef CONFIG_DEBUG_STACK_USAGE
726 static __thread unsigned int max_stack_usage;
727 #endif
728 
729 void qemu_free_stack(void *stack, size_t sz)
730 {
731 #ifdef CONFIG_DEBUG_STACK_USAGE
732     unsigned int usage;
733     void *ptr;
734 
735     for (ptr = stack + getpagesize(); ptr < stack + sz;
736          ptr += sizeof(uint32_t)) {
737         if (*(uint32_t *)ptr != 0xdeadbeaf) {
738             break;
739         }
740     }
741     usage = sz - (uintptr_t) (ptr - stack);
742     if (usage > max_stack_usage) {
743         error_report("thread %d max stack usage increased from %u to %u",
744                      qemu_get_thread_id(), max_stack_usage, usage);
745         max_stack_usage = usage;
746     }
747 #endif
748 
749     munmap(stack, sz);
750 }
751 
752 void sigaction_invoke(struct sigaction *action,
753                       struct qemu_signalfd_siginfo *info)
754 {
755     siginfo_t si = {};
756     si.si_signo = info->ssi_signo;
757     si.si_errno = info->ssi_errno;
758     si.si_code = info->ssi_code;
759 
760     /* Convert the minimal set of fields defined by POSIX.
761      * Positive si_code values are reserved for kernel-generated
762      * signals, where the valid siginfo fields are determined by
763      * the signal number.  But according to POSIX, it is unspecified
764      * whether SI_USER and SI_QUEUE have values less than or equal to
765      * zero.
766      */
767     if (info->ssi_code == SI_USER || info->ssi_code == SI_QUEUE ||
768         info->ssi_code <= 0) {
769         /* SIGTERM, etc.  */
770         si.si_pid = info->ssi_pid;
771         si.si_uid = info->ssi_uid;
772     } else if (info->ssi_signo == SIGILL || info->ssi_signo == SIGFPE ||
773                info->ssi_signo == SIGSEGV || info->ssi_signo == SIGBUS) {
774         si.si_addr = (void *)(uintptr_t)info->ssi_addr;
775     } else if (info->ssi_signo == SIGCHLD) {
776         si.si_pid = info->ssi_pid;
777         si.si_status = info->ssi_status;
778         si.si_uid = info->ssi_uid;
779     }
780     action->sa_sigaction(info->ssi_signo, &si, NULL);
781 }
782