| /* | 
 |  * QEMU access to the auxiliary vector | 
 |  * | 
 |  * Copyright (C) 2013 Red Hat, Inc | 
 |  * | 
 |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
 |  * of this software and associated documentation files (the "Software"), to deal | 
 |  * in the Software without restriction, including without limitation the rights | 
 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
 |  * copies of the Software, and to permit persons to whom the Software is | 
 |  * furnished to do so, subject to the following conditions: | 
 |  * | 
 |  * The above copyright notice and this permission notice shall be included in | 
 |  * all copies or substantial portions of the Software. | 
 |  * | 
 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 
 |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
 |  * THE SOFTWARE. | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 |  | 
 | #ifdef CONFIG_GETAUXVAL | 
 | /* Don't inline this in qemu/osdep.h, because pulling in <sys/auxv.h> for | 
 |    the system declaration of getauxval pulls in the system <elf.h>, which | 
 |    conflicts with qemu's version.  */ | 
 |  | 
 | #include <sys/auxv.h> | 
 |  | 
 | unsigned long qemu_getauxval(unsigned long key) | 
 | { | 
 |     return getauxval(key); | 
 | } | 
 | #elif defined(__linux__) | 
 | #include "elf.h" | 
 |  | 
 | /* Our elf.h doesn't contain Elf32_auxv_t and Elf64_auxv_t, which is ok because | 
 |    that just makes it easier to define it properly for the host here.  */ | 
 | typedef struct { | 
 |     unsigned long a_type; | 
 |     unsigned long a_val; | 
 | } ElfW_auxv_t; | 
 |  | 
 | static const ElfW_auxv_t *auxv; | 
 |  | 
 | static const ElfW_auxv_t *qemu_init_auxval(void) | 
 | { | 
 |     ElfW_auxv_t *a; | 
 |     ssize_t size = 512, r, ofs; | 
 |     int fd; | 
 |  | 
 |     /* Allocate some initial storage.  Make sure the first entry is set | 
 |        to end-of-list, so that we've got a valid list in case of error.  */ | 
 |     auxv = a = g_malloc(size); | 
 |     a[0].a_type = 0; | 
 |     a[0].a_val = 0; | 
 |  | 
 |     fd = open("/proc/self/auxv", O_RDONLY); | 
 |     if (fd < 0) { | 
 |         return a; | 
 |     } | 
 |  | 
 |     /* Read the first SIZE bytes.  Hopefully, this covers everything.  */ | 
 |     r = read(fd, a, size); | 
 |  | 
 |     if (r == size) { | 
 |         /* Continue to expand until we do get a partial read.  */ | 
 |         do { | 
 |             ofs = size; | 
 |             size *= 2; | 
 |             auxv = a = g_realloc(a, size); | 
 |             r = read(fd, (char *)a + ofs, ofs); | 
 |         } while (r == ofs); | 
 |     } | 
 |  | 
 |     close(fd); | 
 |     return a; | 
 | } | 
 |  | 
 | unsigned long qemu_getauxval(unsigned long type) | 
 | { | 
 |     const ElfW_auxv_t *a = auxv; | 
 |  | 
 |     if (unlikely(a == NULL)) { | 
 |         a = qemu_init_auxval(); | 
 |     } | 
 |  | 
 |     for (; a->a_type != 0; a++) { | 
 |         if (a->a_type == type) { | 
 |             return a->a_val; | 
 |         } | 
 |     } | 
 |  | 
 |     errno = ENOENT; | 
 |     return 0; | 
 | } | 
 |  | 
 | #elif defined(CONFIG_ELF_AUX_INFO) | 
 | #include <sys/auxv.h> | 
 |  | 
 | unsigned long qemu_getauxval(unsigned long type) | 
 | { | 
 |     unsigned long aux = 0; | 
 |     int ret = elf_aux_info(type, &aux, sizeof(aux)); | 
 |     if (ret != 0) { | 
 |         errno = ret; | 
 |     } | 
 |     return aux; | 
 | } | 
 |  | 
 | #else | 
 |  | 
 | unsigned long qemu_getauxval(unsigned long type) | 
 | { | 
 |     errno = ENOSYS; | 
 |     return 0; | 
 | } | 
 |  | 
 | #endif |