1*c21bc6f3SBojan Novković /*- 2*c21bc6f3SBojan Novković * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*c21bc6f3SBojan Novković * 4*c21bc6f3SBojan Novković * Copyright (c) 2023 Bojan Novković <bnovkov@freebsd.org> 5*c21bc6f3SBojan Novković * 6*c21bc6f3SBojan Novković * Redistribution and use in source and binary forms, with or without 7*c21bc6f3SBojan Novković * modification, are permitted provided that the following conditions 8*c21bc6f3SBojan Novković * are met: 9*c21bc6f3SBojan Novković * 1. Redistributions of source code must retain the above copyright 10*c21bc6f3SBojan Novković * notice, this list of conditions and the following disclaimer. 11*c21bc6f3SBojan Novković * 2. Redistributions in binary form must reproduce the above copyright 12*c21bc6f3SBojan Novković * notice, this list of conditions and the following disclaimer in the 13*c21bc6f3SBojan Novković * documentation and/or other materials provided with the distribution. 14*c21bc6f3SBojan Novković * 15*c21bc6f3SBojan Novković * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*c21bc6f3SBojan Novković * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*c21bc6f3SBojan Novković * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*c21bc6f3SBojan Novković * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*c21bc6f3SBojan Novković * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*c21bc6f3SBojan Novković * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*c21bc6f3SBojan Novković * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*c21bc6f3SBojan Novković * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*c21bc6f3SBojan Novković * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*c21bc6f3SBojan Novković * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*c21bc6f3SBojan Novković * SUCH DAMAGE. 26*c21bc6f3SBojan Novković */ 27*c21bc6f3SBojan Novković 28*c21bc6f3SBojan Novković #include <sys/cdefs.h> 29*c21bc6f3SBojan Novković #include <sys/types.h> 30*c21bc6f3SBojan Novković #include <sys/param.h> 31*c21bc6f3SBojan Novković #include <sys/systm.h> 32*c21bc6f3SBojan Novković #include <sys/ctype.h> 33*c21bc6f3SBojan Novković #include <sys/linker.h> 34*c21bc6f3SBojan Novković #include <sys/malloc.h> 35*c21bc6f3SBojan Novković #include <sys/mutex.h> 36*c21bc6f3SBojan Novković 37*c21bc6f3SBojan Novković #include <ddb/ddb.h> 38*c21bc6f3SBojan Novković #include <ddb/db_ctf.h> 39*c21bc6f3SBojan Novković 40*c21bc6f3SBojan Novković static const ctf_header_t * 41*c21bc6f3SBojan Novković db_ctf_fetch_cth(linker_ctf_t *lc) 42*c21bc6f3SBojan Novković { 43*c21bc6f3SBojan Novković return (const ctf_header_t *)lc->ctftab; 44*c21bc6f3SBojan Novković } 45*c21bc6f3SBojan Novković 46*c21bc6f3SBojan Novković /* 47*c21bc6f3SBojan Novković * Tries to look up the ELF symbol -> CTF type identifier mapping by scanning 48*c21bc6f3SBojan Novković * the CTF object section. 49*c21bc6f3SBojan Novković */ 50*c21bc6f3SBojan Novković static uint32_t 51*c21bc6f3SBojan Novković sym_to_objtoff(linker_ctf_t *lc, const Elf_Sym *sym, const Elf_Sym *symtab, 52*c21bc6f3SBojan Novković const Elf_Sym *symtab_end) 53*c21bc6f3SBojan Novković { 54*c21bc6f3SBojan Novković const ctf_header_t *hp = db_ctf_fetch_cth(lc); 55*c21bc6f3SBojan Novković uint32_t objtoff = hp->cth_objtoff; 56*c21bc6f3SBojan Novković const size_t idwidth = 4; 57*c21bc6f3SBojan Novković 58*c21bc6f3SBojan Novković /* Ignore non-object symbols */ 59*c21bc6f3SBojan Novković if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) { 60*c21bc6f3SBojan Novković return (DB_CTF_INVALID_OFF); 61*c21bc6f3SBojan Novković } 62*c21bc6f3SBojan Novković /* Sanity check */ 63*c21bc6f3SBojan Novković if (!(sym >= symtab && sym <= symtab_end)) { 64*c21bc6f3SBojan Novković return (DB_CTF_INVALID_OFF); 65*c21bc6f3SBojan Novković } 66*c21bc6f3SBojan Novković 67*c21bc6f3SBojan Novković for (const Elf_Sym *symp = symtab; symp < symtab_end; symp++) { 68*c21bc6f3SBojan Novković /* Make sure we do not go beyond the objtoff section */ 69*c21bc6f3SBojan Novković if (objtoff >= hp->cth_funcoff) { 70*c21bc6f3SBojan Novković objtoff = DB_CTF_INVALID_OFF; 71*c21bc6f3SBojan Novković break; 72*c21bc6f3SBojan Novković } 73*c21bc6f3SBojan Novković if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) { 74*c21bc6f3SBojan Novković continue; 75*c21bc6f3SBojan Novković } 76*c21bc6f3SBojan Novković if (symp->st_shndx == SHN_ABS && symp->st_value == 0) { 77*c21bc6f3SBojan Novković continue; 78*c21bc6f3SBojan Novković } 79*c21bc6f3SBojan Novković 80*c21bc6f3SBojan Novković /* Skip non-object symbols */ 81*c21bc6f3SBojan Novković if (ELF_ST_TYPE(symp->st_info) != STT_OBJECT) { 82*c21bc6f3SBojan Novković continue; 83*c21bc6f3SBojan Novković } 84*c21bc6f3SBojan Novković if (symp == sym) { 85*c21bc6f3SBojan Novković break; 86*c21bc6f3SBojan Novković } 87*c21bc6f3SBojan Novković objtoff += idwidth; 88*c21bc6f3SBojan Novković } 89*c21bc6f3SBojan Novković 90*c21bc6f3SBojan Novković return (objtoff); 91*c21bc6f3SBojan Novković } 92*c21bc6f3SBojan Novković 93*c21bc6f3SBojan Novković /* 94*c21bc6f3SBojan Novković * Returns the size of CTF type 't'. 95*c21bc6f3SBojan Novković */ 96*c21bc6f3SBojan Novković static u_int 97*c21bc6f3SBojan Novković db_ctf_type_size(struct ctf_type_v3 *t) 98*c21bc6f3SBojan Novković { 99*c21bc6f3SBojan Novković u_int vlen, kind, ssize; 100*c21bc6f3SBojan Novković u_int type_struct_size, kind_size; 101*c21bc6f3SBojan Novković 102*c21bc6f3SBojan Novković vlen = CTF_V3_INFO_VLEN(t->ctt_info); 103*c21bc6f3SBojan Novković kind = CTF_V3_INFO_KIND(t->ctt_info); 104*c21bc6f3SBojan Novković ssize = ((t->ctt_size == CTF_V3_LSIZE_SENT) ? CTF_TYPE_LSIZE(t) : 105*c21bc6f3SBojan Novković t->ctt_size); 106*c21bc6f3SBojan Novković type_struct_size = ((t->ctt_size == CTF_V3_LSIZE_SENT) ? 107*c21bc6f3SBojan Novković sizeof(struct ctf_type_v3) : 108*c21bc6f3SBojan Novković sizeof(struct ctf_stype_v3)); 109*c21bc6f3SBojan Novković 110*c21bc6f3SBojan Novković switch (kind) { 111*c21bc6f3SBojan Novković case CTF_K_INTEGER: 112*c21bc6f3SBojan Novković case CTF_K_FLOAT: 113*c21bc6f3SBojan Novković kind_size = sizeof(uint32_t); 114*c21bc6f3SBojan Novković break; 115*c21bc6f3SBojan Novković case CTF_K_ARRAY: 116*c21bc6f3SBojan Novković kind_size = sizeof(struct ctf_array_v3); 117*c21bc6f3SBojan Novković break; 118*c21bc6f3SBojan Novković case CTF_K_UNION: 119*c21bc6f3SBojan Novković case CTF_K_STRUCT: 120*c21bc6f3SBojan Novković kind_size = vlen * 121*c21bc6f3SBojan Novković ((ssize < CTF_V3_LSTRUCT_THRESH) ? 122*c21bc6f3SBojan Novković sizeof(struct ctf_member_v3) : 123*c21bc6f3SBojan Novković sizeof(struct ctf_lmember_v3)); 124*c21bc6f3SBojan Novković break; 125*c21bc6f3SBojan Novković case CTF_K_ENUM: 126*c21bc6f3SBojan Novković kind_size = vlen * sizeof(struct ctf_enum); 127*c21bc6f3SBojan Novković break; 128*c21bc6f3SBojan Novković case CTF_K_FUNCTION: 129*c21bc6f3SBojan Novković kind_size = vlen * sizeof(uint32_t); 130*c21bc6f3SBojan Novković break; 131*c21bc6f3SBojan Novković case CTF_K_UNKNOWN: 132*c21bc6f3SBojan Novković case CTF_K_FORWARD: 133*c21bc6f3SBojan Novković case CTF_K_POINTER: 134*c21bc6f3SBojan Novković case CTF_K_TYPEDEF: 135*c21bc6f3SBojan Novković case CTF_K_VOLATILE: 136*c21bc6f3SBojan Novković case CTF_K_CONST: 137*c21bc6f3SBojan Novković case CTF_K_RESTRICT: 138*c21bc6f3SBojan Novković kind_size = 0; 139*c21bc6f3SBojan Novković break; 140*c21bc6f3SBojan Novković default: 141*c21bc6f3SBojan Novković db_printf("Error: invalid CTF type kind encountered\n"); 142*c21bc6f3SBojan Novković return (-1); 143*c21bc6f3SBojan Novković } 144*c21bc6f3SBojan Novković 145*c21bc6f3SBojan Novković return (type_struct_size + kind_size); 146*c21bc6f3SBojan Novković } 147*c21bc6f3SBojan Novković 148*c21bc6f3SBojan Novković /* 149*c21bc6f3SBojan Novković * Looks up type name 'name' in the CTF string table and returns the 150*c21bc6f3SBojan Novković * corresponding CTF type struct, if any. 151*c21bc6f3SBojan Novković */ 152*c21bc6f3SBojan Novković struct ctf_type_v3 * 153*c21bc6f3SBojan Novković db_ctf_typename_to_type(linker_ctf_t *lc, const char *name) 154*c21bc6f3SBojan Novković { 155*c21bc6f3SBojan Novković const ctf_header_t *hp = db_ctf_fetch_cth(lc); 156*c21bc6f3SBojan Novković char *start, *cur, *end; 157*c21bc6f3SBojan Novković uint32_t stroff = hp->cth_stroff; 158*c21bc6f3SBojan Novković uint32_t typeoff = hp->cth_typeoff; 159*c21bc6f3SBojan Novković uint32_t name_stroff; 160*c21bc6f3SBojan Novković const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t); 161*c21bc6f3SBojan Novković 162*c21bc6f3SBojan Novković u_int skiplen; 163*c21bc6f3SBojan Novković 164*c21bc6f3SBojan Novković /* Scan ctf strtab for typename. */ 165*c21bc6f3SBojan Novković start = cur = __DECONST(char *, hp) + sizeof(ctf_header_t) + 166*c21bc6f3SBojan Novković hp->cth_stroff; 167*c21bc6f3SBojan Novković end = cur + hp->cth_strlen; 168*c21bc6f3SBojan Novković while (cur < end) { 169*c21bc6f3SBojan Novković if (strcmp(cur, name) == 0) 170*c21bc6f3SBojan Novković break; 171*c21bc6f3SBojan Novković cur += strlen(cur) + 1; 172*c21bc6f3SBojan Novković } 173*c21bc6f3SBojan Novković if (cur >= end) 174*c21bc6f3SBojan Novković return (NULL); 175*c21bc6f3SBojan Novković name_stroff = (uint32_t)(cur - start); 176*c21bc6f3SBojan Novković 177*c21bc6f3SBojan Novković /* Scan for type containing the found stroff. */ 178*c21bc6f3SBojan Novković while (typeoff < stroff) { 179*c21bc6f3SBojan Novković struct ctf_type_v3 *t = 180*c21bc6f3SBojan Novković (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + 181*c21bc6f3SBojan Novković typeoff); 182*c21bc6f3SBojan Novković /* We found the type struct */ 183*c21bc6f3SBojan Novković if (t->ctt_name == name_stroff) { 184*c21bc6f3SBojan Novković break; 185*c21bc6f3SBojan Novković } 186*c21bc6f3SBojan Novković if ((skiplen = db_ctf_type_size(t)) == -1) { 187*c21bc6f3SBojan Novković return (NULL); 188*c21bc6f3SBojan Novković } 189*c21bc6f3SBojan Novković typeoff += skiplen; 190*c21bc6f3SBojan Novković } 191*c21bc6f3SBojan Novković if (typeoff < stroff) { 192*c21bc6f3SBojan Novković return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + 193*c21bc6f3SBojan Novković typeoff); 194*c21bc6f3SBojan Novković } else { /* A type struct was not found */ 195*c21bc6f3SBojan Novković return (NULL); 196*c21bc6f3SBojan Novković } 197*c21bc6f3SBojan Novković } 198*c21bc6f3SBojan Novković 199*c21bc6f3SBojan Novković /* 200*c21bc6f3SBojan Novković * Wrapper used by the kernel linker CTF routines. 201*c21bc6f3SBojan Novković * Currently used to implement lookup of CTF types accross all loaded kernel 202*c21bc6f3SBojan Novković * modules. 203*c21bc6f3SBojan Novković */ 204*c21bc6f3SBojan Novković bool 205*c21bc6f3SBojan Novković db_ctf_lookup_typename(linker_ctf_t *lc, const char *typename) 206*c21bc6f3SBojan Novković { 207*c21bc6f3SBojan Novković return (db_ctf_typename_to_type(lc, typename) != NULL); 208*c21bc6f3SBojan Novković } 209*c21bc6f3SBojan Novković 210*c21bc6f3SBojan Novković /* 211*c21bc6f3SBojan Novković * Returns the type corresponding to the 'typeid' parameter from the CTF type 212*c21bc6f3SBojan Novković * section. 213*c21bc6f3SBojan Novković */ 214*c21bc6f3SBojan Novković struct ctf_type_v3 * 215*c21bc6f3SBojan Novković db_ctf_typeid_to_type(db_ctf_sym_data_t sd, uint32_t typeid) 216*c21bc6f3SBojan Novković { 217*c21bc6f3SBojan Novković const ctf_header_t *hp = db_ctf_fetch_cth(&sd->lc); 218*c21bc6f3SBojan Novković const uint8_t *ctfstart = (const uint8_t *)hp + sizeof(ctf_header_t); 219*c21bc6f3SBojan Novković uint32_t typeoff = hp->cth_typeoff; 220*c21bc6f3SBojan Novković uint32_t stroff = hp->cth_stroff; 221*c21bc6f3SBojan Novković /* CTF typeids start at 0x1 */ 222*c21bc6f3SBojan Novković size_t cur_typeid = 1; 223*c21bc6f3SBojan Novković u_int skiplen; 224*c21bc6f3SBojan Novković 225*c21bc6f3SBojan Novković /* Find corresponding type */ 226*c21bc6f3SBojan Novković while (typeoff < stroff) { 227*c21bc6f3SBojan Novković struct ctf_type_v3 *t = 228*c21bc6f3SBojan Novković (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + 229*c21bc6f3SBojan Novković typeoff); 230*c21bc6f3SBojan Novković 231*c21bc6f3SBojan Novković /* We found the type struct */ 232*c21bc6f3SBojan Novković if (cur_typeid == typeid) { 233*c21bc6f3SBojan Novković break; 234*c21bc6f3SBojan Novković } 235*c21bc6f3SBojan Novković cur_typeid++; 236*c21bc6f3SBojan Novković if ((skiplen = db_ctf_type_size(t)) == -1) { 237*c21bc6f3SBojan Novković return (NULL); 238*c21bc6f3SBojan Novković } 239*c21bc6f3SBojan Novković typeoff += skiplen; 240*c21bc6f3SBojan Novković } 241*c21bc6f3SBojan Novković if (typeoff < stroff) { 242*c21bc6f3SBojan Novković return (struct ctf_type_v3 *)(__DECONST(uint8_t *, ctfstart) + 243*c21bc6f3SBojan Novković typeoff); 244*c21bc6f3SBojan Novković } else { /* A type struct was not found */ 245*c21bc6f3SBojan Novković return (NULL); 246*c21bc6f3SBojan Novković } 247*c21bc6f3SBojan Novković } 248*c21bc6f3SBojan Novković 249*c21bc6f3SBojan Novković const char * 250*c21bc6f3SBojan Novković db_ctf_stroff_to_str(db_ctf_sym_data_t sd, uint32_t off) 251*c21bc6f3SBojan Novković { 252*c21bc6f3SBojan Novković const ctf_header_t *hp = db_ctf_fetch_cth(&sd->lc); 253*c21bc6f3SBojan Novković uint32_t stroff = hp->cth_stroff + off; 254*c21bc6f3SBojan Novković const char *ret; 255*c21bc6f3SBojan Novković 256*c21bc6f3SBojan Novković if (stroff >= (hp->cth_stroff + hp->cth_strlen)) { 257*c21bc6f3SBojan Novković return ("invalid"); 258*c21bc6f3SBojan Novković } 259*c21bc6f3SBojan Novković ret = ((const char *)hp + sizeof(ctf_header_t)) + stroff; 260*c21bc6f3SBojan Novković if (*ret == '\0') { 261*c21bc6f3SBojan Novković return (NULL); 262*c21bc6f3SBojan Novković } 263*c21bc6f3SBojan Novković 264*c21bc6f3SBojan Novković return (ret); 265*c21bc6f3SBojan Novković } 266*c21bc6f3SBojan Novković 267*c21bc6f3SBojan Novković /* 268*c21bc6f3SBojan Novković * Tries to find the type of the symbol specified in 'sd->sym'. 269*c21bc6f3SBojan Novković */ 270*c21bc6f3SBojan Novković struct ctf_type_v3 * 271*c21bc6f3SBojan Novković db_ctf_sym_to_type(db_ctf_sym_data_t sd) 272*c21bc6f3SBojan Novković { 273*c21bc6f3SBojan Novković uint32_t objtoff, typeid; 274*c21bc6f3SBojan Novković const Elf_Sym *symtab, *symtab_end; 275*c21bc6f3SBojan Novković 276*c21bc6f3SBojan Novković if (sd->sym == NULL) { 277*c21bc6f3SBojan Novković return (NULL); 278*c21bc6f3SBojan Novković } 279*c21bc6f3SBojan Novković symtab = sd->lc.symtab; 280*c21bc6f3SBojan Novković symtab_end = symtab + sd->lc.nsym; 281*c21bc6f3SBojan Novković 282*c21bc6f3SBojan Novković objtoff = sym_to_objtoff(&sd->lc, sd->sym, symtab, symtab_end); 283*c21bc6f3SBojan Novković /* Sanity check - should not happen */ 284*c21bc6f3SBojan Novković if (objtoff == DB_CTF_INVALID_OFF) { 285*c21bc6f3SBojan Novković db_printf("Could not find CTF object offset.\n"); 286*c21bc6f3SBojan Novković return (NULL); 287*c21bc6f3SBojan Novković } 288*c21bc6f3SBojan Novković 289*c21bc6f3SBojan Novković typeid = *( 290*c21bc6f3SBojan Novković const uint32_t *)(sd->lc.ctftab + sizeof(ctf_header_t) + objtoff); 291*c21bc6f3SBojan Novković 292*c21bc6f3SBojan Novković return (db_ctf_typeid_to_type(sd, typeid)); 293*c21bc6f3SBojan Novković } 294*c21bc6f3SBojan Novković 295*c21bc6f3SBojan Novković /* 296*c21bc6f3SBojan Novković * Scans the kernel file and all loaded module for symbol 'name'. 297*c21bc6f3SBojan Novković */ 298*c21bc6f3SBojan Novković int 299*c21bc6f3SBojan Novković db_ctf_find_symbol(const char *name, db_ctf_sym_data_t sd) 300*c21bc6f3SBojan Novković { 301*c21bc6f3SBojan Novković int error; 302*c21bc6f3SBojan Novković c_linker_sym_t lsym = NULL; 303*c21bc6f3SBojan Novković 304*c21bc6f3SBojan Novković error = linker_ctf_lookup_sym_ddb(name, &lsym, &sd->lc); 305*c21bc6f3SBojan Novković if (error != 0) { 306*c21bc6f3SBojan Novković db_printf( 307*c21bc6f3SBojan Novković "failed to look up symbol and CTF info for %s: error %d\n", 308*c21bc6f3SBojan Novković name, error); 309*c21bc6f3SBojan Novković return (error); 310*c21bc6f3SBojan Novković } 311*c21bc6f3SBojan Novković sd->sym = __DECONST(Elf_Sym *, lsym); 312*c21bc6f3SBojan Novković 313*c21bc6f3SBojan Novković return (0); 314*c21bc6f3SBojan Novković } 315*c21bc6f3SBojan Novković 316*c21bc6f3SBojan Novković /* 317*c21bc6f3SBojan Novković * Scans the kernel file and all loaded module for type specified by 'typename'. 318*c21bc6f3SBojan Novković */ 319*c21bc6f3SBojan Novković struct ctf_type_v3 * 320*c21bc6f3SBojan Novković db_ctf_find_typename(db_ctf_sym_data_t sd, const char *typename) 321*c21bc6f3SBojan Novković { 322*c21bc6f3SBojan Novković if (linker_ctf_lookup_typename_ddb(&sd->lc, typename) != 0) { 323*c21bc6f3SBojan Novković return (NULL); 324*c21bc6f3SBojan Novković } 325*c21bc6f3SBojan Novković return (db_ctf_typename_to_type(&sd->lc, typename)); 326*c21bc6f3SBojan Novković } 327