1 /* $OpenBSD: db_ctf.c,v 1.4 2016/09/18 13:31:12 jasper Exp $ */ 2 3 /* 4 * Copyright (c) 2016 Jasper Lievisse Adriaanse <jasper@openbsd.org> 5 * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/stdint.h> 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/exec.h> 25 26 #include <machine/db_machdep.h> 27 28 #include <ddb/db_extern.h> 29 #include <ddb/db_sym.h> 30 #include <ddb/db_elf.h> 31 #include <ddb/db_output.h> 32 33 #include <sys/exec_elf.h> 34 #include <sys/ctf.h> 35 #include <sys/malloc.h> 36 #include <lib/libz/zlib.h> 37 38 extern db_symtab_t db_symtab; 39 40 struct ddb_ctf { 41 struct ctf_header *cth; 42 const char *data; 43 off_t dlen; 44 unsigned int ctf_found; 45 unsigned int nsyms; 46 size_t ctftab_size; 47 const char *ctftab; 48 }; 49 50 struct ddb_ctf db_ctf; 51 52 /* 53 * We need a way to get the number of symbols, so (ab)use db_elf_sym_forall() 54 * to give us the count. 55 */ 56 struct db_ctf_forall_arg { 57 int cnt; 58 db_sym_t sym; 59 }; 60 61 static const char *db_ctf_lookup_name(unsigned int); 62 static const char *db_ctf_idx2sym(size_t *, unsigned char); 63 static const char *db_elf_find_ctftab(db_symtab_t *, size_t *); 64 static char *db_ctf_decompress(const char *, size_t, off_t); 65 static int db_ctf_print_functions(); 66 static void db_ctf_forall(db_sym_t, char *, char *, int, void *); 67 68 /* 69 * Entrypoint to verify CTF presence, initialize the header, decompress 70 * the data, etc. 71 */ 72 void 73 db_ctf_init(void) 74 { 75 struct db_ctf_forall_arg dfa; 76 db_symtab_t *stab = &db_symtab; 77 const char *ctftab; 78 size_t ctftab_size; 79 int nsyms; 80 81 /* Assume nothing was correct found until proven otherwise. */ 82 db_ctf.ctf_found = 0; 83 84 ctftab = db_elf_find_ctftab(stab, &ctftab_size); 85 if (ctftab == NULL) { 86 return; 87 } 88 89 db_ctf.ctftab = ctftab; 90 db_ctf.ctftab_size = ctftab_size; 91 db_ctf.cth = (struct ctf_header *)ctftab; 92 db_ctf.dlen = db_ctf.cth->cth_stroff + db_ctf.cth->cth_strlen; 93 94 /* Now decompress the section, take into account to skip the header */ 95 if (db_ctf.cth->cth_flags & CTF_F_COMPRESS) { 96 if ((db_ctf.data = 97 db_ctf_decompress(db_ctf.ctftab + sizeof(*db_ctf.cth), 98 db_ctf.ctftab_size - sizeof(*db_ctf.cth), 99 db_ctf.dlen)) == NULL) 100 return; 101 } else { 102 db_printf("Unsupported non-compressed CTF section encountered\n"); 103 return; 104 } 105 106 /* 107 * Lookup the total number of kernel symbols. It's unlikely for the 108 * kernel to have zero symbols so bail out if that's what we end 109 * up finding. 110 */ 111 dfa.cnt = 0; 112 db_elf_sym_forall(db_ctf_forall, &dfa); 113 nsyms = -dfa.cnt; 114 115 if (nsyms == 0) 116 return; 117 else 118 db_ctf.nsyms = nsyms; 119 120 /* We made it this far, everything seems fine. */ 121 db_ctf.ctf_found = 1; 122 } 123 124 static void 125 db_ctf_forall(db_sym_t sym, char *name, char *suff, int pre, void *varg) 126 { 127 struct db_ctf_forall_arg *arg = varg; 128 129 if (arg->cnt-- == 0) 130 arg->sym = sym; 131 } 132 133 /* 134 * Internal helper function - return a pointer to the CTF table 135 * for the current symbol table (and update the size). 136 */ 137 static const char * 138 db_elf_find_ctftab(db_symtab_t *stab, size_t *size) 139 { 140 Elf_Ehdr *elf = STAB_TO_EHDR(stab); 141 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf); 142 char *shstrtab; 143 int i; 144 145 shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset; 146 147 for (i = 0; i < elf->e_shnum; i++) { 148 if ((shp[i].sh_flags & SHF_ALLOC) != 0 && 149 strcmp(ELF_CTF, shstrtab+shp[i].sh_name) == 0) { 150 *size = shp[i].sh_size; 151 return ((char *)elf + shp[i].sh_offset); 152 } 153 } 154 155 return (NULL); 156 } 157 158 void 159 db_dump_ctf_header(void) 160 { 161 if (!db_ctf.ctf_found) 162 return; 163 164 db_printf("CTF header found at %p (%ld)\n", db_ctf.ctftab, 165 db_ctf.ctftab_size); 166 db_printf("cth_magic: 0x%04x\n", db_ctf.cth->cth_magic); 167 db_printf("cth_verion: %d\n", db_ctf.cth->cth_version); 168 db_printf("cth_flags: 0x%02x", db_ctf.cth->cth_flags); 169 if (db_ctf.cth->cth_flags & CTF_F_COMPRESS) { 170 db_printf(" (compressed)"); 171 } 172 db_printf("\n"); 173 db_printf("cth_parlabel: %s\n", 174 db_ctf_lookup_name(db_ctf.cth->cth_parlabel)); 175 db_printf("cth_parname: %s\n", 176 db_ctf_lookup_name(db_ctf.cth->cth_parname)); 177 db_printf("cth_lbloff: %d\n", db_ctf.cth->cth_lbloff); 178 db_printf("cth_objtoff: %d\n", db_ctf.cth->cth_objtoff); 179 db_printf("cth_funcoff: %d\n", db_ctf.cth->cth_funcoff); 180 db_printf("cth_typeoff: %d\n", db_ctf.cth->cth_typeoff); 181 db_printf("cth_stroff: %d\n", db_ctf.cth->cth_stroff); 182 db_printf("cth_strlen: %d\n", db_ctf.cth->cth_strlen); 183 184 #if 1 185 db_ctf_print_functions(); 186 #endif 187 } 188 189 /* 190 * Convert an index to a symbol name while ensuring the type is matched. 191 * It must be noted this only works if the CTF table has the same order 192 * as the symbol table. 193 */ 194 static const char * 195 db_ctf_idx2sym(size_t *idx, unsigned char type) 196 { 197 db_symtab_t *stab = &db_symtab; 198 Elf_Sym *symp, *symtab_start; 199 const Elf_Sym *st; 200 char *strtab; 201 size_t i; 202 203 if (stab->private == NULL) 204 return (NULL); 205 206 strtab = db_elf_find_strtab(stab); 207 if (strtab == NULL) 208 return (NULL); 209 210 symtab_start = STAB_TO_SYMSTART(stab); 211 symp = symtab_start; 212 213 for (i = *idx + 1; i < db_ctf.nsyms; i++) { 214 st = &symp[i]; 215 216 if (ELF_ST_TYPE(st->st_info) != type) 217 continue; 218 219 *idx = i; 220 return strtab + st->st_name; 221 } 222 223 return (NULL); 224 } 225 226 /* 227 * For a given function name, return the number of arguments. 228 */ 229 int 230 db_ctf_func_numargs(const char *funcname) 231 { 232 const char *s; 233 unsigned short *fsp, kind, vlen; 234 size_t idx = 0; 235 int nargs; 236 237 if (!db_ctf.ctf_found) 238 return (0); 239 240 fsp = (unsigned short *)(db_ctf.data + db_ctf.cth->cth_funcoff); 241 while (fsp < (unsigned short *)(db_ctf.data + db_ctf.cth->cth_typeoff)) { 242 kind = CTF_INFO_KIND(*fsp); 243 vlen = CTF_INFO_VLEN(*fsp); 244 s = db_ctf_idx2sym(&idx, STT_FUNC); 245 fsp++; 246 247 if (kind == CTF_K_UNKNOWN && vlen == 0) 248 continue; 249 250 nargs = 0; 251 if (s != NULL) { 252 /* 253 * We have to keep increasing fsp++ while walking the 254 * table even if we discard the value at that location. 255 * This is required to keep a moving index. 256 * 257 * First increment for the return type, then for each 258 * parameter type. 259 */ 260 fsp++; 261 262 while (vlen-- > 0) { 263 nargs++; 264 fsp++; 265 } 266 267 if (strncmp(funcname, s, strlen(funcname)) == 0) { 268 return (nargs); 269 } 270 } 271 } 272 273 return (0); 274 } 275 276 static int 277 db_ctf_print_functions(void) 278 { 279 unsigned short *fsp, kind, vlen; 280 size_t idx = 0, i = 0; 281 const char *s; 282 int l; 283 284 if (!db_ctf.ctf_found) 285 return 1; 286 287 fsp = (unsigned short *)(db_ctf.data + db_ctf.cth->cth_funcoff); 288 while (fsp < (unsigned short *)(db_ctf.data + db_ctf.cth->cth_typeoff)) { 289 kind = CTF_INFO_KIND(*fsp); 290 vlen = CTF_INFO_VLEN(*fsp); 291 fsp++; 292 293 if (kind == CTF_K_UNKNOWN && vlen == 0) 294 continue; 295 296 l = db_printf(" [%zu] FUNC ", i++); 297 if ((s = db_ctf_idx2sym(&idx, STT_FUNC)) != NULL) 298 db_printf("(%s)", s); 299 db_printf(" returns: %u args: (", *fsp++); 300 while (vlen-- > 0) 301 db_printf("%u%s", *fsp++, (vlen > 0) ? ", " : ""); 302 db_printf(") idx: %zu\n", idx); 303 } 304 db_printf("\n"); 305 return 0; 306 } 307 308 static const char * 309 db_ctf_lookup_name(unsigned int offset) 310 { 311 const char *name; 312 313 if (CTF_NAME_STID(offset) != CTF_STRTAB_0) 314 return "external"; 315 316 if (CTF_NAME_OFFSET(offset) >= db_ctf.cth->cth_strlen) 317 return "exceeds strlab"; 318 319 if (db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset) >= db_ctf.dlen) 320 return "invalid"; 321 322 name = db_ctf.data + db_ctf.cth->cth_stroff + CTF_NAME_OFFSET(offset); 323 if (*name == '\0') 324 return "(anon)"; 325 326 return name; 327 } 328 329 static char * 330 db_ctf_decompress(const char *buf, size_t size, off_t len) 331 { 332 z_stream stream; 333 char *data; 334 int error; 335 336 /* XXX: drop malloc(9) usage */ 337 data = malloc(len, M_TEMP, M_WAITOK|M_ZERO|M_CANFAIL); 338 if (data == NULL) { 339 return (NULL); 340 } 341 342 memset(&stream, 0, sizeof(stream)); 343 stream.next_in = (void *)buf; 344 stream.avail_in = size; 345 stream.next_out = data; 346 stream.avail_out = len; 347 348 if ((error = inflateInit(&stream)) != Z_OK) { 349 db_printf("zlib inflateInit failed: %s", zError(error)); 350 goto exit; 351 } 352 353 if ((error = inflate(&stream, Z_FINISH)) != Z_STREAM_END) { 354 db_printf("zlib inflate failed: %s", zError(error)); 355 inflateEnd(&stream); 356 goto exit; 357 } 358 359 if ((error = inflateEnd(&stream)) != Z_OK) { 360 db_printf("zlib inflateEnd failed: %s", zError(error)); 361 goto exit; 362 } 363 364 if (stream.total_out != len) { 365 db_printf("decompression failed: %llu != %llu", 366 stream.total_out, len); 367 goto exit; 368 } 369 370 return (data); 371 372 exit: 373 free(data, M_DEVBUF, sizeof(*data)); 374 return (NULL); 375 } 376