1 1.12 riastrad /* $NetBSD: t_rtld_r_debug.c,v 1.12 2025/04/16 12:05:52 riastradh Exp $ */ 2 1.1 kamil 3 1.1 kamil /* 4 1.1 kamil * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 1.1 kamil * All rights reserved. 6 1.1 kamil * 7 1.1 kamil * Redistribution and use in source and binary forms, with or without 8 1.1 kamil * modification, are permitted provided that the following conditions 9 1.1 kamil * are met: 10 1.1 kamil * 1. Redistributions of source code must retain the above copyright 11 1.1 kamil * notice, this list of conditions and the following disclaimer. 12 1.1 kamil * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 kamil * notice, this list of conditions and the following disclaimer in the 14 1.1 kamil * documentation and/or other materials provided with the distribution. 15 1.1 kamil * 16 1.1 kamil * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 1.1 kamil * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 1.1 kamil * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 1.1 kamil * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 kamil * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 1.1 kamil * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 kamil * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 1.1 kamil * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 kamil * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 1.1 kamil * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 1.1 kamil * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 1.1 kamil * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 kamil */ 29 1.1 kamil 30 1.10 riastrad #include <sys/cdefs.h> 31 1.12 riastrad __RCSID("$NetBSD: t_rtld_r_debug.c,v 1.12 2025/04/16 12:05:52 riastradh Exp $"); 32 1.10 riastrad 33 1.1 kamil #include <sys/types.h> 34 1.1 kamil 35 1.1 kamil #include <atf-c.h> 36 1.1 kamil #include <dlfcn.h> 37 1.1 kamil #include <link_elf.h> 38 1.1 kamil #include <stdbool.h> 39 1.1 kamil 40 1.1 kamil #include "h_macros.h" 41 1.1 kamil 42 1.1 kamil static long int 43 1.1 kamil getauxval(unsigned int type) 44 1.1 kamil { 45 1.1 kamil const AuxInfo *aux; 46 1.1 kamil 47 1.1 kamil for (aux = _dlauxinfo(); aux->a_type != AT_NULL; ++aux) { 48 1.3 roy if (type == aux->a_type) 49 1.1 kamil return aux->a_v; 50 1.1 kamil } 51 1.1 kamil 52 1.1 kamil return 0; 53 1.1 kamil } 54 1.1 kamil 55 1.1 kamil static Elf_Dyn * 56 1.1 kamil get_dynamic_section(void) 57 1.1 kamil { 58 1.1 kamil uintptr_t relocbase = (uintptr_t)~0U; 59 1.1 kamil const Elf_Phdr *phdr; 60 1.1 kamil Elf_Half phnum; 61 1.1 kamil const Elf_Phdr *phlimit, *dynphdr; 62 1.1 kamil 63 1.1 kamil phdr = (void *)getauxval(AT_PHDR); 64 1.1 kamil phnum = (Elf_Half)getauxval(AT_PHNUM); 65 1.1 kamil 66 1.8 riastrad printf("AT_PHDR=%p\n", phdr); 67 1.8 riastrad printf("AT_PHNUM=%d\n", phnum); 68 1.8 riastrad 69 1.7 riastrad ATF_REQUIRE(phdr != NULL); 70 1.7 riastrad ATF_REQUIRE(phnum != (Elf_Half)~0); 71 1.1 kamil 72 1.1 kamil phlimit = phdr + phnum; 73 1.1 kamil dynphdr = NULL; 74 1.1 kamil 75 1.1 kamil for (; phdr < phlimit; ++phdr) { 76 1.8 riastrad printf("phdr %p: type=%d flags=0x%x" 77 1.8 riastrad " vaddr=0x%lx paddr=0x%lx" 78 1.8 riastrad " filesz=0x%lx memsz=0x%lx" 79 1.8 riastrad " align=0x%lx\n", 80 1.8 riastrad phdr, phdr->p_type, phdr->p_flags, 81 1.8 riastrad (long)phdr->p_vaddr, (long)phdr->p_paddr, 82 1.8 riastrad (long)phdr->p_filesz, (long)phdr->p_memsz, 83 1.8 riastrad (long)phdr->p_align); 84 1.3 roy if (phdr->p_type == PT_DYNAMIC) 85 1.3 roy dynphdr = phdr; 86 1.3 roy if (phdr->p_type == PT_PHDR) 87 1.3 roy relocbase = (uintptr_t)phdr - phdr->p_vaddr; 88 1.3 roy } 89 1.1 kamil 90 1.1 kamil return (Elf_Dyn *)((uint8_t *)dynphdr->p_vaddr + relocbase); 91 1.1 kamil } 92 1.1 kamil 93 1.11 riastrad static const struct r_debug * 94 1.1 kamil get_rtld_r_debug(void) 95 1.1 kamil { 96 1.11 riastrad const struct r_debug *debug = NULL; 97 1.1 kamil Elf_Dyn *dynp; 98 1.1 kamil 99 1.1 kamil for (dynp = get_dynamic_section(); dynp->d_tag != DT_NULL; dynp++) { 100 1.8 riastrad printf("dynp %p: tag=%ld val=0x%lx\n", dynp, 101 1.8 riastrad (long)dynp->d_tag, (long)dynp->d_un.d_val); 102 1.11 riastrad #ifdef __mips__ 103 1.11 riastrad if (dynp->d_tag == DT_MIPS_RLD_MAP) { 104 1.11 riastrad debug = (const void *)*(Elf_Addr *)dynp->d_un.d_ptr; 105 1.11 riastrad break; 106 1.11 riastrad } 107 1.11 riastrad if (dynp->d_tag == DT_MIPS_RLD_MAP_REL) { 108 1.11 riastrad debug = (const void *)*(Elf_Addr *)((Elf_Addr)dynp + 109 1.11 riastrad dynp->d_un.d_val); 110 1.12 riastrad break; 111 1.11 riastrad } 112 1.11 riastrad #else 113 1.1 kamil if (dynp->d_tag == DT_DEBUG) { 114 1.1 kamil debug = (void *)dynp->d_un.d_val; 115 1.1 kamil break; 116 1.1 kamil } 117 1.11 riastrad #endif 118 1.1 kamil } 119 1.7 riastrad ATF_REQUIRE(debug != NULL); 120 1.1 kamil 121 1.1 kamil return debug; 122 1.1 kamil } 123 1.1 kamil 124 1.1 kamil static void 125 1.11 riastrad check_r_debug_return_link_map(const char *name, const struct link_map **rmap) 126 1.1 kamil { 127 1.11 riastrad const struct r_debug *debug; 128 1.11 riastrad const struct link_map *map; 129 1.1 kamil void *loader; 130 1.1 kamil bool found; 131 1.1 kamil 132 1.1 kamil loader = NULL; 133 1.1 kamil debug = get_rtld_r_debug(); 134 1.7 riastrad ATF_REQUIRE(debug != NULL); 135 1.5 riastrad ATF_CHECK_EQ_MSG(debug->r_version, R_DEBUG_VERSION, 136 1.5 riastrad "debug->r_version=%d R_DEBUG_VERSION=%d", 137 1.5 riastrad debug->r_version, R_DEBUG_VERSION); 138 1.1 kamil map = debug->r_map; 139 1.1 kamil ATF_CHECK(map != NULL); 140 1.1 kamil 141 1.1 kamil for (found = false; map; map = map->l_next) { 142 1.1 kamil if (strstr(map->l_name, name) != NULL) { 143 1.1 kamil if (rmap) 144 1.1 kamil *rmap = map; 145 1.1 kamil found = true; 146 1.1 kamil } else if (strstr(map->l_name, "ld.elf_so") != NULL) { 147 1.1 kamil loader = (void *)map->l_addr; 148 1.1 kamil } 149 1.1 kamil } 150 1.1 kamil ATF_CHECK(found); 151 1.1 kamil ATF_CHECK(loader != NULL); 152 1.1 kamil ATF_CHECK(debug->r_brk != NULL); 153 1.5 riastrad ATF_CHECK_EQ_MSG(debug->r_state, RT_CONSISTENT, 154 1.5 riastrad "debug->r_state=%d RT_CONSISTENT=%d", 155 1.5 riastrad debug->r_state, RT_CONSISTENT); 156 1.5 riastrad ATF_CHECK_EQ_MSG(debug->r_ldbase, loader, 157 1.5 riastrad "debug->r_ldbase=%p loader=%p", 158 1.5 riastrad debug->r_ldbase, loader); 159 1.1 kamil } 160 1.1 kamil 161 1.1 kamil ATF_TC(self); 162 1.1 kamil ATF_TC_HEAD(self, tc) 163 1.1 kamil { 164 1.1 kamil atf_tc_set_md_var(tc, "descr", "check whether r_debug is well-formed"); 165 1.1 kamil } 166 1.1 kamil ATF_TC_BODY(self, tc) 167 1.1 kamil { 168 1.1 kamil check_r_debug_return_link_map("t_rtld_r_debug", NULL); 169 1.1 kamil } 170 1.1 kamil 171 1.1 kamil ATF_TC(dlopen); 172 1.1 kamil ATF_TC_HEAD(dlopen, tc) 173 1.1 kamil { 174 1.1 kamil atf_tc_set_md_var(tc, "descr", 175 1.6 rillig "check whether r_debug is well-formed after a dlopen(3) call"); 176 1.1 kamil } 177 1.1 kamil ATF_TC_BODY(dlopen, tc) 178 1.1 kamil { 179 1.1 kamil void *handle; 180 1.11 riastrad const struct link_map *r_map, *map; 181 1.1 kamil 182 1.1 kamil handle = dlopen("libutil.so", RTLD_LAZY); 183 1.5 riastrad ATF_REQUIRE_MSG(handle, "dlopen: %s", dlerror()); 184 1.1 kamil 185 1.1 kamil check_r_debug_return_link_map("libutil.so", &r_map); 186 1.1 kamil 187 1.4 riastrad ATF_REQUIRE_EQ_MSG(dlinfo(handle, RTLD_DI_LINKMAP, &map), 0, 188 1.4 riastrad "dlinfo: %s", dlerror()); 189 1.1 kamil 190 1.5 riastrad ATF_CHECK_EQ_MSG(map, r_map, "map=%p r_map=%p", map, r_map); 191 1.5 riastrad ATF_CHECK_EQ_MSG(dlclose(handle), 0, "dlclose: %s", dlerror()); 192 1.1 kamil } 193 1.1 kamil 194 1.1 kamil ATF_TP_ADD_TCS(tp) 195 1.1 kamil { 196 1.1 kamil ATF_TP_ADD_TC(tp, self); 197 1.1 kamil ATF_TP_ADD_TC(tp, dlopen); 198 1.1 kamil return atf_no_error(); 199 1.1 kamil } 200