Print this page
libdtrace: attempt to resolve FORWARD types to concrete types
1730 DTrace should ignore type information from modules with cth_parlabel mismatches
Reviewed by: Keith Wesolowski <keith.wesolowski@joyent.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libdtrace/common/dt_module.c
+++ new/usr/src/lib/libdtrace/common/dt_module.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25 /*
26 26 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
27 27 */
28 28
29 29 #include <sys/types.h>
30 30 #include <sys/modctl.h>
31 31 #include <sys/kobj.h>
32 32 #include <sys/kobj_impl.h>
33 33 #include <sys/sysmacros.h>
34 34 #include <sys/elf.h>
35 35 #include <sys/task.h>
36 36
37 37 #include <unistd.h>
38 38 #include <project.h>
39 39 #include <strings.h>
40 40 #include <stdlib.h>
41 41 #include <libelf.h>
42 42 #include <limits.h>
43 43 #include <assert.h>
44 44 #include <errno.h>
45 45 #include <dirent.h>
46 46
47 47 #include <dt_strtab.h>
48 48 #include <dt_module.h>
49 49 #include <dt_impl.h>
50 50
51 51 static const char *dt_module_strtab; /* active strtab for qsort callbacks */
52 52
53 53 static void
54 54 dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id)
55 55 {
56 56 dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree];
57 57 uint_t h;
58 58
59 59 assert(dmp->dm_symfree < dmp->dm_nsymelems + 1);
60 60
61 61 dsp->ds_symid = id;
62 62 h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
63 63 dsp->ds_next = dmp->dm_symbuckets[h];
64 64 dmp->dm_symbuckets[h] = dmp->dm_symfree++;
65 65 }
66 66
67 67 static uint_t
68 68 dt_module_syminit32(dt_module_t *dmp)
69 69 {
70 70 #if STT_NUM != (STT_TLS + 1)
71 71 #error "STT_NUM has grown. update dt_module_syminit32()"
72 72 #endif
73 73
74 74 const Elf32_Sym *sym = dmp->dm_symtab.cts_data;
75 75 const char *base = dmp->dm_strtab.cts_data;
76 76 size_t ss_size = dmp->dm_strtab.cts_size;
77 77 uint_t i, n = dmp->dm_nsymelems;
78 78 uint_t asrsv = 0;
79 79
80 80 for (i = 0; i < n; i++, sym++) {
81 81 const char *name = base + sym->st_name;
82 82 uchar_t type = ELF32_ST_TYPE(sym->st_info);
83 83
84 84 if (type >= STT_NUM || type == STT_SECTION)
85 85 continue; /* skip sections and unknown types */
86 86
87 87 if (sym->st_name == 0 || sym->st_name >= ss_size)
88 88 continue; /* skip null or invalid names */
89 89
90 90 if (sym->st_value != 0 &&
91 91 (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
92 92 asrsv++; /* reserve space in the address map */
93 93
94 94 dt_module_symhash_insert(dmp, name, i);
95 95 }
96 96
97 97 return (asrsv);
98 98 }
99 99
100 100 static uint_t
101 101 dt_module_syminit64(dt_module_t *dmp)
102 102 {
103 103 #if STT_NUM != (STT_TLS + 1)
104 104 #error "STT_NUM has grown. update dt_module_syminit64()"
105 105 #endif
106 106
107 107 const Elf64_Sym *sym = dmp->dm_symtab.cts_data;
108 108 const char *base = dmp->dm_strtab.cts_data;
109 109 size_t ss_size = dmp->dm_strtab.cts_size;
110 110 uint_t i, n = dmp->dm_nsymelems;
111 111 uint_t asrsv = 0;
112 112
113 113 for (i = 0; i < n; i++, sym++) {
114 114 const char *name = base + sym->st_name;
115 115 uchar_t type = ELF64_ST_TYPE(sym->st_info);
116 116
117 117 if (type >= STT_NUM || type == STT_SECTION)
118 118 continue; /* skip sections and unknown types */
119 119
120 120 if (sym->st_name == 0 || sym->st_name >= ss_size)
121 121 continue; /* skip null or invalid names */
122 122
123 123 if (sym->st_value != 0 &&
124 124 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
125 125 asrsv++; /* reserve space in the address map */
126 126
127 127 dt_module_symhash_insert(dmp, name, i);
128 128 }
129 129
130 130 return (asrsv);
131 131 }
132 132
133 133 /*
134 134 * Sort comparison function for 32-bit symbol address-to-name lookups. We sort
135 135 * symbols by value. If values are equal, we prefer the symbol that is
136 136 * non-zero sized, typed, not weak, or lexically first, in that order.
137 137 */
138 138 static int
139 139 dt_module_symcomp32(const void *lp, const void *rp)
140 140 {
141 141 Elf32_Sym *lhs = *((Elf32_Sym **)lp);
142 142 Elf32_Sym *rhs = *((Elf32_Sym **)rp);
143 143
144 144 if (lhs->st_value != rhs->st_value)
145 145 return (lhs->st_value > rhs->st_value ? 1 : -1);
146 146
147 147 if ((lhs->st_size == 0) != (rhs->st_size == 0))
148 148 return (lhs->st_size == 0 ? 1 : -1);
149 149
150 150 if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
151 151 (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE))
152 152 return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
153 153
154 154 if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) !=
155 155 (ELF32_ST_BIND(rhs->st_info) == STB_WEAK))
156 156 return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
157 157
158 158 return (strcmp(dt_module_strtab + lhs->st_name,
159 159 dt_module_strtab + rhs->st_name));
160 160 }
161 161
162 162 /*
163 163 * Sort comparison function for 64-bit symbol address-to-name lookups. We sort
164 164 * symbols by value. If values are equal, we prefer the symbol that is
165 165 * non-zero sized, typed, not weak, or lexically first, in that order.
166 166 */
167 167 static int
168 168 dt_module_symcomp64(const void *lp, const void *rp)
169 169 {
170 170 Elf64_Sym *lhs = *((Elf64_Sym **)lp);
171 171 Elf64_Sym *rhs = *((Elf64_Sym **)rp);
172 172
173 173 if (lhs->st_value != rhs->st_value)
174 174 return (lhs->st_value > rhs->st_value ? 1 : -1);
175 175
176 176 if ((lhs->st_size == 0) != (rhs->st_size == 0))
177 177 return (lhs->st_size == 0 ? 1 : -1);
178 178
179 179 if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
180 180 (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE))
181 181 return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
182 182
183 183 if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) !=
184 184 (ELF64_ST_BIND(rhs->st_info) == STB_WEAK))
185 185 return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
186 186
187 187 return (strcmp(dt_module_strtab + lhs->st_name,
188 188 dt_module_strtab + rhs->st_name));
189 189 }
190 190
191 191 static void
192 192 dt_module_symsort32(dt_module_t *dmp)
193 193 {
194 194 Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data;
195 195 Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap;
196 196 const dt_sym_t *dsp = dmp->dm_symchains + 1;
197 197 uint_t i, n = dmp->dm_symfree;
198 198
199 199 for (i = 1; i < n; i++, dsp++) {
200 200 Elf32_Sym *sym = symtab + dsp->ds_symid;
201 201 if (sym->st_value != 0 &&
202 202 (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
203 203 *sympp++ = sym;
204 204 }
205 205
206 206 dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap);
207 207 assert(dmp->dm_aslen <= dmp->dm_asrsv);
208 208
209 209 dt_module_strtab = dmp->dm_strtab.cts_data;
210 210 qsort(dmp->dm_asmap, dmp->dm_aslen,
211 211 sizeof (Elf32_Sym *), dt_module_symcomp32);
212 212 dt_module_strtab = NULL;
213 213 }
214 214
215 215 static void
216 216 dt_module_symsort64(dt_module_t *dmp)
217 217 {
218 218 Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data;
219 219 Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap;
220 220 const dt_sym_t *dsp = dmp->dm_symchains + 1;
221 221 uint_t i, n = dmp->dm_symfree;
222 222
223 223 for (i = 1; i < n; i++, dsp++) {
224 224 Elf64_Sym *sym = symtab + dsp->ds_symid;
225 225 if (sym->st_value != 0 &&
226 226 (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
227 227 *sympp++ = sym;
228 228 }
229 229
230 230 dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap);
231 231 assert(dmp->dm_aslen <= dmp->dm_asrsv);
232 232
233 233 dt_module_strtab = dmp->dm_strtab.cts_data;
234 234 qsort(dmp->dm_asmap, dmp->dm_aslen,
235 235 sizeof (Elf64_Sym *), dt_module_symcomp64);
236 236 dt_module_strtab = NULL;
237 237 }
238 238
239 239 static GElf_Sym *
240 240 dt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst)
241 241 {
242 242 if (dst != NULL) {
243 243 dst->st_name = src->st_name;
244 244 dst->st_info = src->st_info;
245 245 dst->st_other = src->st_other;
246 246 dst->st_shndx = src->st_shndx;
247 247 dst->st_value = src->st_value;
248 248 dst->st_size = src->st_size;
249 249 }
250 250
251 251 return (dst);
252 252 }
253 253
254 254 static GElf_Sym *
255 255 dt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst)
256 256 {
257 257 if (dst != NULL)
258 258 bcopy(src, dst, sizeof (GElf_Sym));
259 259
260 260 return (dst);
261 261 }
262 262
263 263 static GElf_Sym *
264 264 dt_module_symname32(dt_module_t *dmp, const char *name,
265 265 GElf_Sym *symp, uint_t *idp)
266 266 {
267 267 const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
268 268 const char *strtab = dmp->dm_strtab.cts_data;
269 269
270 270 const Elf32_Sym *sym;
271 271 const dt_sym_t *dsp;
272 272 uint_t i, h;
273 273
274 274 if (dmp->dm_nsymelems == 0)
275 275 return (NULL);
276 276
277 277 h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
278 278
279 279 for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
280 280 dsp = &dmp->dm_symchains[i];
281 281 sym = symtab + dsp->ds_symid;
282 282
283 283 if (strcmp(name, strtab + sym->st_name) == 0) {
284 284 if (idp != NULL)
285 285 *idp = dsp->ds_symid;
286 286 return (dt_module_symgelf32(sym, symp));
287 287 }
288 288 }
289 289
290 290 return (NULL);
291 291 }
292 292
293 293 static GElf_Sym *
294 294 dt_module_symname64(dt_module_t *dmp, const char *name,
295 295 GElf_Sym *symp, uint_t *idp)
296 296 {
297 297 const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
298 298 const char *strtab = dmp->dm_strtab.cts_data;
299 299
300 300 const Elf64_Sym *sym;
301 301 const dt_sym_t *dsp;
302 302 uint_t i, h;
303 303
304 304 if (dmp->dm_nsymelems == 0)
305 305 return (NULL);
306 306
307 307 h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
308 308
309 309 for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
310 310 dsp = &dmp->dm_symchains[i];
311 311 sym = symtab + dsp->ds_symid;
312 312
313 313 if (strcmp(name, strtab + sym->st_name) == 0) {
314 314 if (idp != NULL)
315 315 *idp = dsp->ds_symid;
316 316 return (dt_module_symgelf64(sym, symp));
317 317 }
318 318 }
319 319
320 320 return (NULL);
321 321 }
322 322
323 323 static GElf_Sym *
324 324 dt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr,
325 325 GElf_Sym *symp, uint_t *idp)
326 326 {
327 327 const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap;
328 328 const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
329 329 const Elf32_Sym *sym;
330 330
331 331 uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
332 332 Elf32_Addr v;
333 333
334 334 if (dmp->dm_aslen == 0)
335 335 return (NULL);
336 336
337 337 while (hi - lo > 1) {
338 338 mid = (lo + hi) / 2;
339 339 if (addr >= asmap[mid]->st_value)
340 340 lo = mid;
341 341 else
342 342 hi = mid;
343 343 }
344 344
345 345 i = addr < asmap[hi]->st_value ? lo : hi;
346 346 sym = asmap[i];
347 347 v = sym->st_value;
348 348
349 349 /*
350 350 * If the previous entry has the same value, improve our choice. The
351 351 * order of equal-valued symbols is determined by the comparison func.
352 352 */
353 353 while (i-- != 0 && asmap[i]->st_value == v)
354 354 sym = asmap[i];
355 355
356 356 if (addr - sym->st_value < MAX(sym->st_size, 1)) {
357 357 if (idp != NULL)
358 358 *idp = (uint_t)(sym - symtab);
359 359 return (dt_module_symgelf32(sym, symp));
360 360 }
361 361
362 362 return (NULL);
363 363 }
364 364
365 365 static GElf_Sym *
366 366 dt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr,
367 367 GElf_Sym *symp, uint_t *idp)
368 368 {
369 369 const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap;
370 370 const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
371 371 const Elf64_Sym *sym;
372 372
373 373 uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
374 374 Elf64_Addr v;
375 375
376 376 if (dmp->dm_aslen == 0)
377 377 return (NULL);
378 378
379 379 while (hi - lo > 1) {
380 380 mid = (lo + hi) / 2;
381 381 if (addr >= asmap[mid]->st_value)
382 382 lo = mid;
383 383 else
384 384 hi = mid;
385 385 }
386 386
387 387 i = addr < asmap[hi]->st_value ? lo : hi;
388 388 sym = asmap[i];
389 389 v = sym->st_value;
390 390
391 391 /*
392 392 * If the previous entry has the same value, improve our choice. The
393 393 * order of equal-valued symbols is determined by the comparison func.
394 394 */
395 395 while (i-- != 0 && asmap[i]->st_value == v)
396 396 sym = asmap[i];
397 397
398 398 if (addr - sym->st_value < MAX(sym->st_size, 1)) {
399 399 if (idp != NULL)
400 400 *idp = (uint_t)(sym - symtab);
401 401 return (dt_module_symgelf64(sym, symp));
402 402 }
403 403
404 404 return (NULL);
405 405 }
406 406
407 407 static const dt_modops_t dt_modops_32 = {
408 408 dt_module_syminit32,
409 409 dt_module_symsort32,
410 410 dt_module_symname32,
411 411 dt_module_symaddr32
412 412 };
413 413
414 414 static const dt_modops_t dt_modops_64 = {
415 415 dt_module_syminit64,
416 416 dt_module_symsort64,
417 417 dt_module_symname64,
418 418 dt_module_symaddr64
419 419 };
420 420
421 421 dt_module_t *
422 422 dt_module_create(dtrace_hdl_t *dtp, const char *name)
423 423 {
424 424 long pid;
425 425 char *eptr;
426 426 dt_ident_t *idp;
427 427 uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
428 428 dt_module_t *dmp;
429 429
430 430 for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
431 431 if (strcmp(dmp->dm_name, name) == 0)
432 432 return (dmp);
433 433 }
434 434
435 435 if ((dmp = malloc(sizeof (dt_module_t))) == NULL)
436 436 return (NULL); /* caller must handle allocation failure */
437 437
438 438 bzero(dmp, sizeof (dt_module_t));
439 439 (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name));
440 440 dt_list_append(&dtp->dt_modlist, dmp);
441 441 dmp->dm_next = dtp->dt_mods[h];
442 442 dtp->dt_mods[h] = dmp;
443 443 dtp->dt_nmods++;
444 444
445 445 if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
446 446 dmp->dm_ops = &dt_modops_64;
447 447 else
448 448 dmp->dm_ops = &dt_modops_32;
449 449
450 450 /*
451 451 * Modules for userland processes are special. They always refer to a
452 452 * specific process and have a copy of their CTF data from a specific
453 453 * instant in time. Any dt_module_t that begins with 'pid' is a module
454 454 * for a specific process, much like how any probe description that
455 455 * begins with 'pid' is special. pid123 refers to process 123. A module
456 456 * that is just 'pid' refers specifically to pid$target. This is
457 457 * generally done as D does not currently allow for macros to be
458 458 * evaluated when working with types.
459 459 */
460 460 if (strncmp(dmp->dm_name, "pid", 3) == 0) {
461 461 errno = 0;
462 462 if (dmp->dm_name[3] == '\0') {
463 463 idp = dt_idhash_lookup(dtp->dt_macros, "target");
464 464 if (idp != NULL && idp->di_id != 0)
465 465 dmp->dm_pid = idp->di_id;
466 466 } else {
467 467 pid = strtol(dmp->dm_name + 3, &eptr, 10);
468 468 if (errno == 0 && *eptr == '\0')
469 469 dmp->dm_pid = (pid_t)pid;
470 470 else
471 471 dt_dprintf("encountered malformed pid "
472 472 "module: %s\n", dmp->dm_name);
473 473 }
474 474 }
475 475
476 476 return (dmp);
477 477 }
478 478
479 479 dt_module_t *
480 480 dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name)
481 481 {
482 482 uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
483 483 dt_module_t *dmp;
484 484
485 485 for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
486 486 if (strcmp(dmp->dm_name, name) == 0)
487 487 return (dmp);
488 488 }
489 489
490 490 return (NULL);
491 491 }
492 492
493 493 /*ARGSUSED*/
494 494 dt_module_t *
495 495 dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp)
496 496 {
497 497 return (ctfp ? ctf_getspecific(ctfp) : NULL);
498 498 }
499 499
500 500 static int
501 501 dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
502 502 {
503 503 const char *s;
504 504 size_t shstrs;
505 505 GElf_Shdr sh;
506 506 Elf_Data *dp;
507 507 Elf_Scn *sp;
508 508
509 509 if (elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1)
510 510 return (dt_set_errno(dtp, EDT_NOTLOADED));
511 511
512 512 for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
513 513 if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
514 514 (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
515 515 continue; /* skip any malformed sections */
516 516
517 517 if (sh.sh_type == ctsp->cts_type &&
518 518 sh.sh_entsize == ctsp->cts_entsize &&
519 519 strcmp(s, ctsp->cts_name) == 0)
520 520 break; /* section matches specification */
521 521 }
522 522
523 523 /*
524 524 * If the section isn't found, return success but leave cts_data set
525 525 * to NULL and cts_size set to zero for our caller.
526 526 */
527 527 if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL)
528 528 return (0);
529 529
530 530 ctsp->cts_data = dp->d_buf;
531 531 ctsp->cts_size = dp->d_size;
532 532
533 533 dt_dprintf("loaded %s [%s] (%lu bytes)\n",
534 534 dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size);
535 535
536 536 return (0);
537 537 }
538 538
539 539 typedef struct dt_module_cb_arg {
540 540 struct ps_prochandle *dpa_proc;
541 541 dtrace_hdl_t *dpa_dtp;
542 542 dt_module_t *dpa_dmp;
543 543 uint_t dpa_count;
544 544 } dt_module_cb_arg_t;
545 545
546 546 /* ARGSUSED */
547 547 static int
548 548 dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj)
549 549 {
550 550 ctf_file_t *fp;
551 551 dt_module_cb_arg_t *dcp = arg;
552 552
553 553 /* Try to grab a ctf container if it exists */
554 554 fp = Pname_to_ctf(dcp->dpa_proc, obj);
555 555 if (fp != NULL)
556 556 dcp->dpa_count++;
557 557 return (0);
558 558 }
559 559
560 560 /* ARGSUSED */
561 561 static int
562 562 dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj)
563 563 {
564 564 ctf_file_t *fp;
565 565 char buf[MAXPATHLEN], *p;
566 566 dt_module_cb_arg_t *dcp = arg;
567 567 int count = dcp->dpa_count;
568 568 Lmid_t lmid;
569 569
570 570 fp = Pname_to_ctf(dcp->dpa_proc, obj);
571 571 if (fp == NULL)
572 572 return (0);
573 573 fp = ctf_dup(fp);
574 574 if (fp == NULL)
575 575 return (0);
576 576 dcp->dpa_dmp->dm_libctfp[count] = fp;
577 577 /*
578 578 * While it'd be nice to simply use objname here, because of our prior
579 579 * actions we'll always get a resolved object name to its on disk file.
580 580 * Like the pid provider, we need to tell a bit of a lie here. The type
581 581 * that the user thinks of is in terms of the libraries they requested,
582 582 * eg. libc.so.1, they don't care about the fact that it's
583 583 * libc_hwcap.so.1.
584 584 */
585 585 (void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf));
586 586 if ((p = strrchr(buf, '/')) == NULL)
587 587 p = buf;
588 588 else
589 589 p++;
590 590
591 591 /*
592 592 * If for some reason we can't find a link map id for this module, which
593 593 * would be really quite weird. We instead just say the link map id is
594 594 * zero.
595 595 */
596 596 if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0)
597 597 lmid = 0;
598 598
599 599 if (lmid == 0)
600 600 dcp->dpa_dmp->dm_libctfn[count] = strdup(p);
601 601 else
602 602 (void) asprintf(&dcp->dpa_dmp->dm_libctfn[count],
603 603 "LM%lx`%s", lmid, p);
604 604 if (dcp->dpa_dmp->dm_libctfn[count] == NULL)
605 605 return (1);
606 606 ctf_setspecific(fp, dcp->dpa_dmp);
607 607 dcp->dpa_count++;
608 608 return (0);
609 609 }
610 610
611 611 /*
612 612 * We've been asked to load data that belongs to another process. As such we're
613 613 * going to pgrab it at this instant, load everything that we might ever care
614 614 * about, and then drive on. The reason for this is that the process that we're
615 615 * interested in might be changing. As long as we have grabbed it, then this
616 616 * can't be a problem for us.
617 617 *
618 618 * For now, we're actually going to punt on most things and just try to get CTF
619 619 * data, nothing else. Basically this is only useful as a source of type
620 620 * information, we can't go and do the stacktrace lookups, etc.
621 621 */
622 622 static int
623 623 dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp)
624 624 {
625 625 struct ps_prochandle *p;
626 626 dt_module_cb_arg_t arg;
627 627
628 628 /*
629 629 * Note that on success we do not release this hold. We must hold this
630 630 * for our life time.
631 631 */
632 632 p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
633 633 if (p == NULL) {
634 634 dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid);
635 635 return (dt_set_errno(dtp, EDT_CANTLOAD));
636 636 }
637 637 dt_proc_lock(dtp, p);
638 638
639 639 arg.dpa_proc = p;
640 640 arg.dpa_dtp = dtp;
641 641 arg.dpa_dmp = dmp;
642 642 arg.dpa_count = 0;
643 643 if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) {
644 644 dt_dprintf("failed to iterate objects\n");
645 645 dt_proc_release(dtp, p);
646 646 return (dt_set_errno(dtp, EDT_CANTLOAD));
647 647 }
648 648
649 649 if (arg.dpa_count == 0) {
650 650 dt_dprintf("no ctf data present\n");
651 651 dt_proc_unlock(dtp, p);
652 652 dt_proc_release(dtp, p);
653 653 return (dt_set_errno(dtp, EDT_CANTLOAD));
654 654 }
655 655
656 656 dmp->dm_libctfp = malloc(sizeof (ctf_file_t *) * arg.dpa_count);
657 657 if (dmp->dm_libctfp == NULL) {
658 658 dt_proc_unlock(dtp, p);
659 659 dt_proc_release(dtp, p);
660 660 return (dt_set_errno(dtp, EDT_NOMEM));
661 661 }
662 662 bzero(dmp->dm_libctfp, sizeof (ctf_file_t *) * arg.dpa_count);
663 663
664 664 dmp->dm_libctfn = malloc(sizeof (char *) * arg.dpa_count);
665 665 if (dmp->dm_libctfn == NULL) {
666 666 free(dmp->dm_libctfp);
667 667 dt_proc_unlock(dtp, p);
668 668 dt_proc_release(dtp, p);
669 669 return (dt_set_errno(dtp, EDT_NOMEM));
670 670 }
671 671 bzero(dmp->dm_libctfn, sizeof (char *) * arg.dpa_count);
672 672
673 673 dmp->dm_nctflibs = arg.dpa_count;
674 674
675 675 arg.dpa_count = 0;
676 676 if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) {
677 677 dt_proc_unlock(dtp, p);
678 678 dt_module_unload(dtp, dmp);
679 679 dt_proc_release(dtp, p);
680 680 return (dt_set_errno(dtp, EDT_CANTLOAD));
681 681 }
682 682 assert(arg.dpa_count == dmp->dm_nctflibs);
683 683 dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count,
684 684 (int)dmp->dm_pid);
685 685
686 686 dt_proc_unlock(dtp, p);
687 687 dt_proc_release(dtp, p);
688 688 dmp->dm_flags |= DT_DM_LOADED;
689 689
690 690 return (0);
691 691 }
692 692
693 693 int
694 694 dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
695 695 {
696 696 if (dmp->dm_flags & DT_DM_LOADED)
697 697 return (0); /* module is already loaded */
698 698
699 699 if (dmp->dm_pid != 0)
700 700 return (dt_module_load_proc(dtp, dmp));
701 701
702 702 dmp->dm_ctdata.cts_name = ".SUNW_ctf";
703 703 dmp->dm_ctdata.cts_type = SHT_PROGBITS;
704 704 dmp->dm_ctdata.cts_flags = 0;
705 705 dmp->dm_ctdata.cts_data = NULL;
706 706 dmp->dm_ctdata.cts_size = 0;
707 707 dmp->dm_ctdata.cts_entsize = 0;
708 708 dmp->dm_ctdata.cts_offset = 0;
709 709
710 710 dmp->dm_symtab.cts_name = ".symtab";
711 711 dmp->dm_symtab.cts_type = SHT_SYMTAB;
712 712 dmp->dm_symtab.cts_flags = 0;
713 713 dmp->dm_symtab.cts_data = NULL;
714 714 dmp->dm_symtab.cts_size = 0;
715 715 dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ?
716 716 sizeof (Elf64_Sym) : sizeof (Elf32_Sym);
717 717 dmp->dm_symtab.cts_offset = 0;
718 718
719 719 dmp->dm_strtab.cts_name = ".strtab";
720 720 dmp->dm_strtab.cts_type = SHT_STRTAB;
721 721 dmp->dm_strtab.cts_flags = 0;
722 722 dmp->dm_strtab.cts_data = NULL;
723 723 dmp->dm_strtab.cts_size = 0;
724 724 dmp->dm_strtab.cts_entsize = 0;
725 725 dmp->dm_strtab.cts_offset = 0;
726 726
727 727 /*
728 728 * Attempt to load the module's CTF section, symbol table section, and
729 729 * string table section. Note that modules may not contain CTF data:
730 730 * this will result in a successful load_sect but data of size zero.
731 731 * We will then fail if dt_module_getctf() is called, as shown below.
732 732 */
733 733 if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 ||
734 734 dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 ||
735 735 dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) {
736 736 dt_module_unload(dtp, dmp);
737 737 return (-1); /* dt_errno is set for us */
738 738 }
739 739
740 740 /*
741 741 * Allocate the hash chains and hash buckets for symbol name lookup.
742 742 * This is relatively simple since the symbol table is of fixed size
743 743 * and is known in advance. We allocate one extra element since we
744 744 * use element indices instead of pointers and zero is our sentinel.
745 745 */
746 746 dmp->dm_nsymelems =
747 747 dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize;
748 748
749 749 dmp->dm_nsymbuckets = _dtrace_strbuckets;
750 750 dmp->dm_symfree = 1; /* first free element is index 1 */
751 751
752 752 dmp->dm_symbuckets = malloc(sizeof (uint_t) * dmp->dm_nsymbuckets);
753 753 dmp->dm_symchains = malloc(sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);
754 754
755 755 if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) {
756 756 dt_module_unload(dtp, dmp);
757 757 return (dt_set_errno(dtp, EDT_NOMEM));
758 758 }
759 759
760 760 bzero(dmp->dm_symbuckets, sizeof (uint_t) * dmp->dm_nsymbuckets);
761 761 bzero(dmp->dm_symchains, sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);
762 762
763 763 /*
764 764 * Iterate over the symbol table data buffer and insert each symbol
765 765 * name into the name hash if the name and type are valid. Then
766 766 * allocate the address map, fill it in, and sort it.
767 767 */
768 768 dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp);
769 769
770 770 dt_dprintf("hashed %s [%s] (%u symbols)\n",
771 771 dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1);
772 772
773 773 if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) {
774 774 dt_module_unload(dtp, dmp);
775 775 return (dt_set_errno(dtp, EDT_NOMEM));
776 776 }
777 777
778 778 dmp->dm_ops->do_symsort(dmp);
779 779
780 780 dt_dprintf("sorted %s [%s] (%u symbols)\n",
781 781 dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen);
782 782
783 783 dmp->dm_flags |= DT_DM_LOADED;
784 784 return (0);
785 785 }
786 786
787 787 int
788 788 dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
789 789 {
790 790 if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0)
791 791 return (1);
792 792 return (dt_module_getctf(dtp, dmp) != NULL);
793 793 }
794 794
795 795 ctf_file_t *
796 796 dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
797 797 {
798 798 const char *parent;
799 799 dt_module_t *pmp;
800 800 ctf_file_t *pfp;
801 801 int model;
802 802
803 803 if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0)
804 804 return (dmp->dm_ctfp);
805 805
806 806 if (dmp->dm_ops == &dt_modops_64)
807 807 model = CTF_MODEL_LP64;
808 808 else
809 809 model = CTF_MODEL_ILP32;
810 810
811 811 /*
812 812 * If the data model of the module does not match our program data
813 813 * model, then do not permit CTF from this module to be opened and
814 814 * returned to the compiler. If we support mixed data models in the
815 815 * future for combined kernel/user tracing, this can be removed.
816 816 */
817 817 if (dtp->dt_conf.dtc_ctfmodel != model) {
818 818 (void) dt_set_errno(dtp, EDT_DATAMODEL);
819 819 return (NULL);
820 820 }
821 821
822 822 if (dmp->dm_ctdata.cts_size == 0) {
823 823 (void) dt_set_errno(dtp, EDT_NOCTF);
824 824 return (NULL);
825 825 }
826 826
827 827 dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata,
828 828 &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr);
829 829
830 830 if (dmp->dm_ctfp == NULL) {
831 831 (void) dt_set_errno(dtp, EDT_CTF);
832 832 return (NULL);
833 833 }
834 834
835 835 (void) ctf_setmodel(dmp->dm_ctfp, model);
↓ open down ↓ |
835 lines elided |
↑ open up ↑ |
836 836 ctf_setspecific(dmp->dm_ctfp, dmp);
837 837
838 838 if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) {
839 839 if ((pmp = dt_module_create(dtp, parent)) == NULL ||
840 840 (pfp = dt_module_getctf(dtp, pmp)) == NULL) {
841 841 if (pmp == NULL)
842 842 (void) dt_set_errno(dtp, EDT_NOMEM);
843 843 goto err;
844 844 }
845 845
846 + /*
847 + * If the label we claim the parent must have is not actually
848 + * present in the parent module, ignore the CTF entirely
849 + * rather than acquiring possibly bad type references.
850 + */
851 + if (ctf_label_info(pfp, ctf_parent_label(dmp->dm_ctfp),
852 + NULL) == CTF_ERR) {
853 + (void) dt_set_errno(dtp, EDT_BADCTF);
854 + goto err;
855 + }
856 +
846 857 if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) {
847 858 dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
848 859 (void) dt_set_errno(dtp, EDT_CTF);
849 860 goto err;
850 861 }
851 862 }
852 863
853 864 dt_dprintf("loaded CTF container for %s (%p)\n",
854 865 dmp->dm_name, (void *)dmp->dm_ctfp);
855 866
856 867 return (dmp->dm_ctfp);
857 868
858 869 err:
870 + dt_dprintf("could not load CTF container for %s: %s\n",
871 + dmp->dm_name, dtrace_errmsg(dtp, dtrace_errno(dtp)));
859 872 ctf_close(dmp->dm_ctfp);
860 873 dmp->dm_ctfp = NULL;
861 874 return (NULL);
862 875 }
863 876
864 877 /*ARGSUSED*/
865 878 void
866 879 dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
867 880 {
868 881 int i;
869 882
870 883 ctf_close(dmp->dm_ctfp);
871 884 dmp->dm_ctfp = NULL;
872 885
873 886 if (dmp->dm_libctfp != NULL) {
874 887 for (i = 0; i < dmp->dm_nctflibs; i++) {
875 888 ctf_close(dmp->dm_libctfp[i]);
876 889 free(dmp->dm_libctfn[i]);
877 890 }
878 891 free(dmp->dm_libctfp);
879 892 free(dmp->dm_libctfn);
880 893 dmp->dm_libctfp = NULL;
881 894 dmp->dm_nctflibs = 0;
882 895 }
883 896
884 897 bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t));
885 898 bzero(&dmp->dm_symtab, sizeof (ctf_sect_t));
886 899 bzero(&dmp->dm_strtab, sizeof (ctf_sect_t));
887 900
888 901 if (dmp->dm_symbuckets != NULL) {
889 902 free(dmp->dm_symbuckets);
890 903 dmp->dm_symbuckets = NULL;
891 904 }
892 905
893 906 if (dmp->dm_symchains != NULL) {
894 907 free(dmp->dm_symchains);
895 908 dmp->dm_symchains = NULL;
896 909 }
897 910
898 911 if (dmp->dm_asmap != NULL) {
899 912 free(dmp->dm_asmap);
900 913 dmp->dm_asmap = NULL;
901 914 }
902 915
903 916 dmp->dm_symfree = 0;
904 917 dmp->dm_nsymbuckets = 0;
905 918 dmp->dm_nsymelems = 0;
906 919 dmp->dm_asrsv = 0;
907 920 dmp->dm_aslen = 0;
908 921
909 922 dmp->dm_text_va = NULL;
910 923 dmp->dm_text_size = 0;
911 924 dmp->dm_data_va = NULL;
912 925 dmp->dm_data_size = 0;
913 926 dmp->dm_bss_va = NULL;
914 927 dmp->dm_bss_size = 0;
915 928
916 929 if (dmp->dm_extern != NULL) {
917 930 dt_idhash_destroy(dmp->dm_extern);
918 931 dmp->dm_extern = NULL;
919 932 }
920 933
921 934 (void) elf_end(dmp->dm_elf);
922 935 dmp->dm_elf = NULL;
923 936
924 937 dmp->dm_pid = 0;
925 938
926 939 dmp->dm_flags &= ~DT_DM_LOADED;
927 940 }
928 941
929 942 void
930 943 dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
931 944 {
932 945 uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets;
933 946 dt_module_t **dmpp = &dtp->dt_mods[h];
934 947
935 948 dt_list_delete(&dtp->dt_modlist, dmp);
936 949 assert(dtp->dt_nmods != 0);
937 950 dtp->dt_nmods--;
938 951
939 952 /*
940 953 * Now remove this module from its hash chain. We expect to always
941 954 * find the module on its hash chain, so in this loop we assert that
942 955 * we don't run off the end of the list.
943 956 */
944 957 while (*dmpp != dmp) {
945 958 dmpp = &((*dmpp)->dm_next);
946 959 assert(*dmpp != NULL);
947 960 }
948 961
949 962 *dmpp = dmp->dm_next;
950 963
951 964 dt_module_unload(dtp, dmp);
952 965 free(dmp);
953 966 }
954 967
955 968 /*
956 969 * Insert a new external symbol reference into the specified module. The new
957 970 * symbol will be marked as undefined and is assigned a symbol index beyond
958 971 * any existing cached symbols from this module. We use the ident's di_data
959 972 * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol.
960 973 */
961 974 dt_ident_t *
962 975 dt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp,
963 976 const char *name, const dtrace_typeinfo_t *tip)
964 977 {
965 978 dtrace_syminfo_t *sip;
966 979 dt_ident_t *idp;
967 980 uint_t id;
968 981
969 982 if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create(
970 983 "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) {
971 984 (void) dt_set_errno(dtp, EDT_NOMEM);
972 985 return (NULL);
973 986 }
974 987
975 988 if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) {
976 989 (void) dt_set_errno(dtp, EDT_SYMOFLOW);
977 990 return (NULL);
978 991 }
979 992
980 993 if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) {
981 994 (void) dt_set_errno(dtp, EDT_NOMEM);
982 995 return (NULL);
983 996 }
984 997
985 998 idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id,
986 999 _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
987 1000
988 1001 if (idp == NULL) {
989 1002 (void) dt_set_errno(dtp, EDT_NOMEM);
990 1003 free(sip);
991 1004 return (NULL);
992 1005 }
993 1006
994 1007 sip->dts_object = dmp->dm_name;
995 1008 sip->dts_name = idp->di_name;
996 1009 sip->dts_id = idp->di_id;
997 1010
998 1011 idp->di_data = sip;
999 1012 idp->di_ctfp = tip->dtt_ctfp;
1000 1013 idp->di_type = tip->dtt_type;
1001 1014
1002 1015 return (idp);
1003 1016 }
1004 1017
1005 1018 const char *
1006 1019 dt_module_modelname(dt_module_t *dmp)
1007 1020 {
1008 1021 if (dmp->dm_ops == &dt_modops_64)
1009 1022 return ("64-bit");
1010 1023 else
1011 1024 return ("32-bit");
1012 1025 }
1013 1026
1014 1027 /* ARGSUSED */
1015 1028 int
1016 1029 dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp)
1017 1030 {
1018 1031 int i;
1019 1032
1020 1033 for (i = 0; i < dmp->dm_nctflibs; i++) {
1021 1034 if (dmp->dm_libctfp[i] == fp)
1022 1035 return (i);
1023 1036 }
1024 1037
1025 1038 return (-1);
1026 1039 }
1027 1040
1028 1041 /* ARGSUSED */
1029 1042 ctf_file_t *
1030 1043 dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name)
1031 1044 {
1032 1045 int i;
1033 1046
1034 1047 for (i = 0; i < dmp->dm_nctflibs; i++) {
1035 1048 if (strcmp(dmp->dm_libctfn[i], name) == 0)
1036 1049 return (dmp->dm_libctfp[i]);
1037 1050 }
1038 1051
1039 1052 return (NULL);
1040 1053 }
1041 1054
1042 1055 /*
1043 1056 * Update our module cache by adding an entry for the specified module 'name'.
1044 1057 * We create the dt_module_t and populate it using /system/object/<name>/.
1045 1058 */
1046 1059 static void
1047 1060 dt_module_update(dtrace_hdl_t *dtp, const char *name)
1048 1061 {
1049 1062 char fname[MAXPATHLEN];
1050 1063 struct stat64 st;
1051 1064 int fd, err, bits;
1052 1065
1053 1066 dt_module_t *dmp;
1054 1067 const char *s;
1055 1068 size_t shstrs;
1056 1069 GElf_Shdr sh;
1057 1070 Elf_Data *dp;
1058 1071 Elf_Scn *sp;
1059 1072
1060 1073 (void) snprintf(fname, sizeof (fname),
1061 1074 "%s/%s/object", OBJFS_ROOT, name);
1062 1075
1063 1076 if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
1064 1077 (dmp = dt_module_create(dtp, name)) == NULL) {
1065 1078 dt_dprintf("failed to open %s: %s\n", fname, strerror(errno));
1066 1079 (void) close(fd);
1067 1080 return;
1068 1081 }
1069 1082
1070 1083 /*
1071 1084 * Since the module can unload out from under us (and /system/object
1072 1085 * will return ENOENT), tell libelf to cook the entire file now and
1073 1086 * then close the underlying file descriptor immediately. If this
1074 1087 * succeeds, we know that we can continue safely using dmp->dm_elf.
1075 1088 */
1076 1089 dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL);
1077 1090 err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD);
1078 1091 (void) close(fd);
1079 1092
1080 1093 if (dmp->dm_elf == NULL || err == -1 ||
1081 1094 elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) {
1082 1095 dt_dprintf("failed to load %s: %s\n",
1083 1096 fname, elf_errmsg(elf_errno()));
1084 1097 dt_module_destroy(dtp, dmp);
1085 1098 return;
1086 1099 }
1087 1100
1088 1101 switch (gelf_getclass(dmp->dm_elf)) {
1089 1102 case ELFCLASS32:
1090 1103 dmp->dm_ops = &dt_modops_32;
1091 1104 bits = 32;
1092 1105 break;
1093 1106 case ELFCLASS64:
1094 1107 dmp->dm_ops = &dt_modops_64;
1095 1108 bits = 64;
1096 1109 break;
1097 1110 default:
1098 1111 dt_dprintf("failed to load %s: unknown ELF class\n", fname);
1099 1112 dt_module_destroy(dtp, dmp);
1100 1113 return;
1101 1114 }
1102 1115
1103 1116 /*
1104 1117 * Iterate over the section headers locating various sections of
1105 1118 * interest and use their attributes to flesh out the dt_module_t.
1106 1119 */
1107 1120 for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
1108 1121 if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
1109 1122 (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
1110 1123 continue; /* skip any malformed sections */
1111 1124
1112 1125 if (strcmp(s, ".text") == 0) {
1113 1126 dmp->dm_text_size = sh.sh_size;
1114 1127 dmp->dm_text_va = sh.sh_addr;
1115 1128 } else if (strcmp(s, ".data") == 0) {
1116 1129 dmp->dm_data_size = sh.sh_size;
1117 1130 dmp->dm_data_va = sh.sh_addr;
1118 1131 } else if (strcmp(s, ".bss") == 0) {
1119 1132 dmp->dm_bss_size = sh.sh_size;
1120 1133 dmp->dm_bss_va = sh.sh_addr;
1121 1134 } else if (strcmp(s, ".info") == 0 &&
1122 1135 (dp = elf_getdata(sp, NULL)) != NULL) {
1123 1136 bcopy(dp->d_buf, &dmp->dm_info,
1124 1137 MIN(sh.sh_size, sizeof (dmp->dm_info)));
1125 1138 } else if (strcmp(s, ".filename") == 0 &&
1126 1139 (dp = elf_getdata(sp, NULL)) != NULL) {
1127 1140 (void) strlcpy(dmp->dm_file,
1128 1141 dp->d_buf, sizeof (dmp->dm_file));
1129 1142 }
1130 1143 }
1131 1144
1132 1145 dmp->dm_flags |= DT_DM_KERNEL;
1133 1146 dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);
1134 1147
1135 1148 if (dmp->dm_info.objfs_info_primary)
1136 1149 dmp->dm_flags |= DT_DM_PRIMARY;
1137 1150
1138 1151 dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
1139 1152 bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
1140 1153 }
1141 1154
1142 1155 /*
1143 1156 * Unload all the loaded modules and then refresh the module cache with the
1144 1157 * latest list of loaded modules and their address ranges.
1145 1158 */
1146 1159 void
1147 1160 dtrace_update(dtrace_hdl_t *dtp)
1148 1161 {
1149 1162 dt_module_t *dmp;
1150 1163 DIR *dirp;
1151 1164
1152 1165 for (dmp = dt_list_next(&dtp->dt_modlist);
1153 1166 dmp != NULL; dmp = dt_list_next(dmp))
1154 1167 dt_module_unload(dtp, dmp);
1155 1168
1156 1169 /*
1157 1170 * Open /system/object and attempt to create a libdtrace module for
1158 1171 * each kernel module that is loaded on the current system.
1159 1172 */
1160 1173 if (!(dtp->dt_oflags & DTRACE_O_NOSYS) &&
1161 1174 (dirp = opendir(OBJFS_ROOT)) != NULL) {
1162 1175 struct dirent *dp;
1163 1176
1164 1177 while ((dp = readdir(dirp)) != NULL) {
1165 1178 if (dp->d_name[0] != '.')
1166 1179 dt_module_update(dtp, dp->d_name);
1167 1180 }
1168 1181
1169 1182 (void) closedir(dirp);
1170 1183 }
1171 1184
1172 1185 /*
1173 1186 * Look up all the macro identifiers and set di_id to the latest value.
1174 1187 * This code collaborates with dt_lex.l on the use of di_id. We will
1175 1188 * need to implement something fancier if we need to support non-ints.
1176 1189 */
1177 1190 dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid();
1178 1191 dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid();
1179 1192 dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid();
1180 1193 dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
1181 1194 dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
1182 1195 dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
1183 1196 dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
1184 1197 dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
1185 1198 dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
1186 1199 dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();
1187 1200
1188 1201 /*
1189 1202 * Cache the pointers to the modules representing the base executable
1190 1203 * and the run-time linker in the dtrace client handle. Note that on
1191 1204 * x86 krtld is folded into unix, so if we don't find it, use unix
1192 1205 * instead.
1193 1206 */
1194 1207 dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix");
1195 1208 dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld");
1196 1209 if (dtp->dt_rtld == NULL)
1197 1210 dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix");
1198 1211
1199 1212 /*
1200 1213 * If this is the first time we are initializing the module list,
1201 1214 * remove the module for genunix from the module list and then move it
1202 1215 * to the front of the module list. We do this so that type and symbol
1203 1216 * queries encounter genunix and thereby optimize for the common case
1204 1217 * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below.
1205 1218 */
1206 1219 if (dtp->dt_exec != NULL &&
1207 1220 dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) {
1208 1221 dt_list_delete(&dtp->dt_modlist, dtp->dt_exec);
1209 1222 dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec);
1210 1223 }
1211 1224 }
1212 1225
1213 1226 static dt_module_t *
1214 1227 dt_module_from_object(dtrace_hdl_t *dtp, const char *object)
1215 1228 {
1216 1229 int err = EDT_NOMOD;
1217 1230 dt_module_t *dmp;
1218 1231
1219 1232 switch ((uintptr_t)object) {
1220 1233 case (uintptr_t)DTRACE_OBJ_EXEC:
1221 1234 dmp = dtp->dt_exec;
1222 1235 break;
1223 1236 case (uintptr_t)DTRACE_OBJ_RTLD:
1224 1237 dmp = dtp->dt_rtld;
1225 1238 break;
1226 1239 case (uintptr_t)DTRACE_OBJ_CDEFS:
1227 1240 dmp = dtp->dt_cdefs;
1228 1241 break;
1229 1242 case (uintptr_t)DTRACE_OBJ_DDEFS:
1230 1243 dmp = dtp->dt_ddefs;
1231 1244 break;
1232 1245 default:
1233 1246 dmp = dt_module_create(dtp, object);
1234 1247 err = EDT_NOMEM;
1235 1248 }
1236 1249
1237 1250 if (dmp == NULL)
1238 1251 (void) dt_set_errno(dtp, err);
1239 1252
1240 1253 return (dmp);
1241 1254 }
1242 1255
1243 1256 /*
1244 1257 * Exported interface to look up a symbol by name. We return the GElf_Sym and
1245 1258 * complete symbol information for the matching symbol.
1246 1259 */
1247 1260 int
1248 1261 dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name,
1249 1262 GElf_Sym *symp, dtrace_syminfo_t *sip)
1250 1263 {
1251 1264 dt_module_t *dmp;
1252 1265 dt_ident_t *idp;
1253 1266 uint_t n, id;
1254 1267 GElf_Sym sym;
1255 1268
1256 1269 uint_t mask = 0; /* mask of dt_module flags to match */
1257 1270 uint_t bits = 0; /* flag bits that must be present */
1258 1271
1259 1272 if (object != DTRACE_OBJ_EVERY &&
1260 1273 object != DTRACE_OBJ_KMODS &&
1261 1274 object != DTRACE_OBJ_UMODS) {
1262 1275 if ((dmp = dt_module_from_object(dtp, object)) == NULL)
1263 1276 return (-1); /* dt_errno is set for us */
1264 1277
1265 1278 if (dt_module_load(dtp, dmp) == -1)
1266 1279 return (-1); /* dt_errno is set for us */
1267 1280 n = 1;
1268 1281
1269 1282 } else {
1270 1283 if (object == DTRACE_OBJ_KMODS)
1271 1284 mask = bits = DT_DM_KERNEL;
1272 1285 else if (object == DTRACE_OBJ_UMODS)
1273 1286 mask = DT_DM_KERNEL;
1274 1287
1275 1288 dmp = dt_list_next(&dtp->dt_modlist);
1276 1289 n = dtp->dt_nmods;
1277 1290 }
1278 1291
1279 1292 if (symp == NULL)
1280 1293 symp = &sym;
1281 1294
1282 1295 for (; n > 0; n--, dmp = dt_list_next(dmp)) {
1283 1296 if ((dmp->dm_flags & mask) != bits)
1284 1297 continue; /* failed to match required attributes */
1285 1298
1286 1299 if (dt_module_load(dtp, dmp) == -1)
1287 1300 continue; /* failed to load symbol table */
1288 1301
1289 1302 if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) {
1290 1303 if (sip != NULL) {
1291 1304 sip->dts_object = dmp->dm_name;
1292 1305 sip->dts_name = (const char *)
1293 1306 dmp->dm_strtab.cts_data + symp->st_name;
1294 1307 sip->dts_id = id;
1295 1308 }
1296 1309 return (0);
1297 1310 }
1298 1311
1299 1312 if (dmp->dm_extern != NULL &&
1300 1313 (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) {
1301 1314 if (symp != &sym) {
1302 1315 symp->st_name = (uintptr_t)idp->di_name;
1303 1316 symp->st_info =
1304 1317 GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
1305 1318 symp->st_other = 0;
1306 1319 symp->st_shndx = SHN_UNDEF;
1307 1320 symp->st_value = 0;
1308 1321 symp->st_size =
1309 1322 ctf_type_size(idp->di_ctfp, idp->di_type);
1310 1323 }
1311 1324
1312 1325 if (sip != NULL) {
1313 1326 sip->dts_object = dmp->dm_name;
1314 1327 sip->dts_name = idp->di_name;
1315 1328 sip->dts_id = idp->di_id;
1316 1329 }
1317 1330
1318 1331 return (0);
1319 1332 }
1320 1333 }
1321 1334
1322 1335 return (dt_set_errno(dtp, EDT_NOSYM));
1323 1336 }
1324 1337
1325 1338 /*
1326 1339 * Exported interface to look up a symbol by address. We return the GElf_Sym
1327 1340 * and complete symbol information for the matching symbol.
1328 1341 */
1329 1342 int
1330 1343 dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr,
1331 1344 GElf_Sym *symp, dtrace_syminfo_t *sip)
1332 1345 {
1333 1346 dt_module_t *dmp;
1334 1347 uint_t id;
1335 1348 const dtrace_vector_t *v = dtp->dt_vector;
1336 1349
1337 1350 if (v != NULL)
1338 1351 return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip));
1339 1352
1340 1353 for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
1341 1354 dmp = dt_list_next(dmp)) {
1342 1355 if (addr - dmp->dm_text_va < dmp->dm_text_size ||
1343 1356 addr - dmp->dm_data_va < dmp->dm_data_size ||
1344 1357 addr - dmp->dm_bss_va < dmp->dm_bss_size)
1345 1358 break;
1346 1359 }
1347 1360
1348 1361 if (dmp == NULL)
1349 1362 return (dt_set_errno(dtp, EDT_NOSYMADDR));
1350 1363
1351 1364 if (dt_module_load(dtp, dmp) == -1)
1352 1365 return (-1); /* dt_errno is set for us */
1353 1366
1354 1367 if (symp != NULL) {
1355 1368 if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL)
1356 1369 return (dt_set_errno(dtp, EDT_NOSYMADDR));
1357 1370 }
1358 1371
1359 1372 if (sip != NULL) {
1360 1373 sip->dts_object = dmp->dm_name;
1361 1374
1362 1375 if (symp != NULL) {
1363 1376 sip->dts_name = (const char *)
1364 1377 dmp->dm_strtab.cts_data + symp->st_name;
↓ open down ↓ |
496 lines elided |
↑ open up ↑ |
1365 1378 sip->dts_id = id;
1366 1379 } else {
1367 1380 sip->dts_name = NULL;
1368 1381 sip->dts_id = 0;
1369 1382 }
1370 1383 }
1371 1384
1372 1385 return (0);
1373 1386 }
1374 1387
1388 +boolean_t
1389 +dt_is_forward_decl(ctf_file_t *file, ctf_id_t type)
1390 +{
1391 + ctf_id_t kind = ctf_type_kind(file, type);
1392 +
1393 + while ((type = ctf_type_reference(file, type)) != CTF_ERR) {
1394 + type = ctf_type_resolve(file, type);
1395 + kind = ctf_type_kind(file, type);
1396 + }
1397 +
1398 + return (kind == CTF_K_FORWARD);
1399 +}
1400 +
1401 +void
1402 +dt_resolve_forward_decl(ctf_file_t **ctfp, ctf_id_t *type)
1403 +{
1404 + char name[DT_TYPE_NAMELEN];
1405 +
1406 + while (dt_is_forward_decl(*ctfp, *type)) {
1407 + char *tag = ctf_type_name(*ctfp, *type, name, sizeof (name));
1408 + dtrace_typeinfo_t dtt;
1409 +
1410 + if (tag != NULL && dt_type_lookup(tag, &dtt) == 0 &&
1411 + (dtt.dtt_ctfp != *ctfp) || dtt.dtt_type != *type) {
1412 + *ctfp = dtt.dtt_ctfp;
1413 + *type = dtt.dtt_type;
1414 + } else {
1415 + /* All we have is the forward definition */
1416 + break;
1417 + }
1418 + }
1419 +}
1420 +
1375 1421 int
1376 1422 dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
1377 1423 dtrace_typeinfo_t *tip)
1378 1424 {
1379 1425 dtrace_typeinfo_t ti;
1380 1426 dt_module_t *dmp;
1381 1427 int found = 0;
1382 1428 ctf_id_t id;
1383 1429 uint_t n, i;
1384 1430 int justone;
1385 1431 ctf_file_t *fp;
1386 1432 char *buf, *p, *q;
1387 1433
1388 1434 uint_t mask = 0; /* mask of dt_module flags to match */
1389 1435 uint_t bits = 0; /* flag bits that must be present */
1390 1436
1391 1437 if (object != DTRACE_OBJ_EVERY &&
1392 1438 object != DTRACE_OBJ_KMODS &&
1393 1439 object != DTRACE_OBJ_UMODS) {
1394 1440 if ((dmp = dt_module_from_object(dtp, object)) == NULL)
1395 1441 return (-1); /* dt_errno is set for us */
1396 1442
1397 1443 if (dt_module_load(dtp, dmp) == -1)
1398 1444 return (-1); /* dt_errno is set for us */
1399 1445 n = 1;
1400 1446 justone = 1;
1401 1447 } else {
1402 1448 if (object == DTRACE_OBJ_KMODS)
1403 1449 mask = bits = DT_DM_KERNEL;
1404 1450 else if (object == DTRACE_OBJ_UMODS)
1405 1451 mask = DT_DM_KERNEL;
1406 1452
1407 1453 dmp = dt_list_next(&dtp->dt_modlist);
1408 1454 n = dtp->dt_nmods;
1409 1455 justone = 0;
1410 1456 }
1411 1457
1412 1458 if (tip == NULL)
1413 1459 tip = &ti;
1414 1460
1415 1461 for (; n > 0; n--, dmp = dt_list_next(dmp)) {
1416 1462 if ((dmp->dm_flags & mask) != bits)
1417 1463 continue; /* failed to match required attributes */
1418 1464
1419 1465 /*
1420 1466 * If we can't load the CTF container, continue on to the next
1421 1467 * module. If our search was scoped to only one module then
1422 1468 * return immediately leaving dt_errno unmodified.
1423 1469 */
1424 1470 if (dt_module_hasctf(dtp, dmp) == 0) {
1425 1471 if (justone)
1426 1472 return (-1);
1427 1473 continue;
1428 1474 }
1429 1475
1430 1476 /*
1431 1477 * Look up the type in the module's CTF container. If our
1432 1478 * match is a forward declaration tag, save this choice in
1433 1479 * 'tip' and keep going in the hope that we will locate the
1434 1480 * underlying structure definition. Otherwise just return.
1435 1481 */
1436 1482 if (dmp->dm_pid == 0) {
1437 1483 id = ctf_lookup_by_name(dmp->dm_ctfp, name);
1438 1484 fp = dmp->dm_ctfp;
1439 1485 } else {
1440 1486 if ((p = strchr(name, '`')) != NULL) {
1441 1487 buf = strdup(name);
1442 1488 if (buf == NULL)
1443 1489 return (dt_set_errno(dtp, EDT_NOMEM));
1444 1490 p = strchr(buf, '`');
1445 1491 if ((q = strchr(p + 1, '`')) != NULL)
1446 1492 p = q;
1447 1493 *p = '\0';
1448 1494 fp = dt_module_getctflib(dtp, dmp, buf);
1449 1495 if (fp == NULL || (id = ctf_lookup_by_name(fp,
1450 1496 p + 1)) == CTF_ERR)
1451 1497 id = CTF_ERR;
1452 1498 free(buf);
1453 1499 } else {
1454 1500 for (i = 0; i < dmp->dm_nctflibs; i++) {
1455 1501 fp = dmp->dm_libctfp[i];
↓ open down ↓ |
71 lines elided |
↑ open up ↑ |
1456 1502 id = ctf_lookup_by_name(fp, name);
1457 1503 if (id != CTF_ERR)
1458 1504 break;
1459 1505 }
1460 1506 }
1461 1507 }
1462 1508 if (id != CTF_ERR) {
1463 1509 tip->dtt_object = dmp->dm_name;
1464 1510 tip->dtt_ctfp = fp;
1465 1511 tip->dtt_type = id;
1466 - if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) !=
1467 - CTF_K_FORWARD)
1512 + if (!dt_is_forward_decl(fp, ctf_type_resolve(fp, id)))
1468 1513 return (0);
1469 1514
1470 1515 found++;
1471 1516 }
1472 1517 }
1473 1518
1474 1519 if (found == 0)
1475 1520 return (dt_set_errno(dtp, EDT_NOTYPE));
1476 1521
1477 1522 return (0);
1478 1523 }
1479 1524
1480 1525 int
1481 1526 dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp,
1482 1527 const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip)
1483 1528 {
1484 1529 dt_module_t *dmp;
1485 1530
1486 1531 tip->dtt_object = NULL;
1487 1532 tip->dtt_ctfp = NULL;
1488 1533 tip->dtt_type = CTF_ERR;
1489 1534 tip->dtt_flags = 0;
1490 1535
1491 1536 if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL)
1492 1537 return (dt_set_errno(dtp, EDT_NOMOD));
1493 1538
1494 1539 if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) {
1495 1540 dt_ident_t *idp =
1496 1541 dt_idhash_lookup(dmp->dm_extern, sip->dts_name);
1497 1542
1498 1543 if (idp == NULL)
1499 1544 return (dt_set_errno(dtp, EDT_NOSYM));
1500 1545
1501 1546 tip->dtt_ctfp = idp->di_ctfp;
1502 1547 tip->dtt_type = idp->di_type;
1503 1548
1504 1549 } else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) {
1505 1550 if (dt_module_getctf(dtp, dmp) == NULL)
1506 1551 return (-1); /* errno is set for us */
1507 1552
1508 1553 tip->dtt_ctfp = dmp->dm_ctfp;
1509 1554 tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id);
1510 1555
1511 1556 if (tip->dtt_type == CTF_ERR) {
1512 1557 dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp);
1513 1558 return (dt_set_errno(dtp, EDT_CTF));
1514 1559 }
1515 1560
1516 1561 } else {
1517 1562 tip->dtt_ctfp = DT_FPTR_CTFP(dtp);
1518 1563 tip->dtt_type = DT_FPTR_TYPE(dtp);
1519 1564 }
1520 1565
1521 1566 tip->dtt_object = dmp->dm_name;
1522 1567 return (0);
1523 1568 }
1524 1569
1525 1570 static dtrace_objinfo_t *
1526 1571 dt_module_info(const dt_module_t *dmp, dtrace_objinfo_t *dto)
1527 1572 {
1528 1573 dto->dto_name = dmp->dm_name;
1529 1574 dto->dto_file = dmp->dm_file;
1530 1575 dto->dto_id = dmp->dm_modid;
1531 1576 dto->dto_flags = 0;
1532 1577
1533 1578 if (dmp->dm_flags & DT_DM_KERNEL)
1534 1579 dto->dto_flags |= DTRACE_OBJ_F_KERNEL;
1535 1580 if (dmp->dm_flags & DT_DM_PRIMARY)
1536 1581 dto->dto_flags |= DTRACE_OBJ_F_PRIMARY;
1537 1582
1538 1583 dto->dto_text_va = dmp->dm_text_va;
1539 1584 dto->dto_text_size = dmp->dm_text_size;
1540 1585 dto->dto_data_va = dmp->dm_data_va;
1541 1586 dto->dto_data_size = dmp->dm_data_size;
1542 1587 dto->dto_bss_va = dmp->dm_bss_va;
1543 1588 dto->dto_bss_size = dmp->dm_bss_size;
1544 1589
1545 1590 return (dto);
1546 1591 }
1547 1592
1548 1593 int
1549 1594 dtrace_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data)
1550 1595 {
1551 1596 const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist);
1552 1597 dtrace_objinfo_t dto;
1553 1598 int rv;
1554 1599
1555 1600 for (; dmp != NULL; dmp = dt_list_next(dmp)) {
1556 1601 if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0)
1557 1602 return (rv);
1558 1603 }
1559 1604
1560 1605 return (0);
1561 1606 }
1562 1607
1563 1608 int
1564 1609 dtrace_object_info(dtrace_hdl_t *dtp, const char *object, dtrace_objinfo_t *dto)
1565 1610 {
1566 1611 dt_module_t *dmp;
1567 1612
1568 1613 if (object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS ||
1569 1614 object == DTRACE_OBJ_UMODS || dto == NULL)
1570 1615 return (dt_set_errno(dtp, EINVAL));
1571 1616
1572 1617 if ((dmp = dt_module_from_object(dtp, object)) == NULL)
1573 1618 return (-1); /* dt_errno is set for us */
1574 1619
1575 1620 if (dt_module_load(dtp, dmp) == -1)
1576 1621 return (-1); /* dt_errno is set for us */
1577 1622
1578 1623 (void) dt_module_info(dmp, dto);
1579 1624 return (0);
1580 1625 }
↓ open down ↓ |
103 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX