1 /* 2 * CDDL HEADER START 3 * 4 * This file and its contents are supplied under the terms of the 5 * Common Development and Distribution License ("CDDL"), version 1.0. 6 * You may only use this file in accordance with the terms of version 7 * 1.0 of the CDDL. 8 * 9 * A full copy of the text of the CDDL should have accompanied this 10 * source. A copy of the CDDL is also available via the Internet at 11 * http://www.illumos.org/license/CDDL. 12 * 13 * CDDL HEADER END 14 */ 15 16 /* 17 * Copyright (c) 2012 by Delphix. All rights reserved. 18 */ 19 20 /* 21 * This file implements an audit library that can be used to force the loading 22 * of helper providers. The default disposition for a helper provider -- USDT 23 * and ustack helpers -- is to load itself from it's containing object's .init 24 * section. In cases where startup time is deemed critical, USDT authors can 25 * use the -xlazyload option to dtrace(8) to disable automatic loading (it's 26 * difficult to make the case for the utility of this feature for anything 27 * other than libc which, indeed, was the sole motivation). If a binary has 28 * been compiled with automatic loading disabled, this audit library may be 29 * used to force automatic loading: 30 * 31 * LD_AUDIT_32=/usr/lib/dtrace/libdaudit.so 32 * LD_AUDIT_64=/usr/lib/dtrace/64/libdaudit.so 33 */ 34 35 #include <link.h> 36 #include <stdio.h> 37 #include <libproc.h> 38 #include <strings.h> 39 40 #include <dlink.h> 41 42 typedef struct obj_list { 43 struct obj_list *ol_next; 44 char *ol_name; 45 uintptr_t ol_addr; 46 Lmid_t ol_lmid; 47 } obj_list_t; 48 49 static obj_list_t *list; 50 51 #pragma init(dtrace_daudit_init) 52 static void 53 dtrace_daudit_init(void) 54 { 55 dtrace_link_init(); 56 } 57 58 /*ARGSUSED*/ 59 uint_t 60 la_version(uint_t version) 61 { 62 return (LAV_CURRENT); 63 } 64 65 /* 66 * Record objects into our linked list as they're loaded. 67 */ 68 /*ARGSUSED*/ 69 uint_t 70 la_objopen(Link_map *lmp, Lmid_t lmid, uintptr_t *cookie) 71 { 72 obj_list_t *node; 73 74 /* 75 * If we can't allocate the next node in our list, we'll try to emit a 76 * message, but it's possible that might fail as well. 77 */ 78 if ((node = malloc(sizeof (obj_list_t))) == NULL) { 79 dprintf(0, "libdaudit: failed to allocate"); 80 return (0); 81 } 82 node->ol_next = list; 83 node->ol_name = strdup(lmp->l_name); 84 node->ol_addr = lmp->l_addr; 85 node->ol_lmid = lmid; 86 list = node; 87 88 return (0); 89 } 90 91 /* 92 * Once the link maps have reached a consistent state, process the list of 93 * objects that were loaded. We need to use libproc to search for the 94 * ___SUNW_dof symbol rather than dlsym(3C) since the symbol is not in the 95 * dynamic (run-time) symbol table (though it is, of course, in the symtab). 96 * Once we find it, we ioctl(2) it to the kernel just as we would have from 97 * the .init section if automatic loading were enabled. 98 */ 99 /*ARGSUSED*/ 100 void 101 la_activity(uintptr_t *cookie, uint_t flags) 102 { 103 struct ps_prochandle *P; 104 int err, ret; 105 GElf_Sym sym; 106 107 if (flags != LA_ACT_CONSISTENT) 108 return; 109 110 while (list != NULL) { 111 obj_list_t *node = list; 112 char *name = node->ol_name; 113 114 list = node->ol_next; 115 116 P = Pgrab(getpid(), PGRAB_RDONLY, &err); 117 ret = Plookup_by_name(P, name, "___SUNW_dof", &sym); 118 Prelease(P, 0); 119 120 if (ret == 0) { 121 dtrace_link_dof((void *)(uintptr_t)sym.st_value, 122 node->ol_lmid, node->ol_name, node->ol_addr); 123 } 124 125 free(node->ol_name); 126 free(node); 127 } 128 } 129