File: drti.c

package info (click to toggle)
dtrace 2.0.5-1
  • links: PTS
  • area: main
  • in suites: sid
  • size: 24,408 kB
  • sloc: ansic: 61,247; sh: 17,997; asm: 1,717; lex: 947; awk: 754; yacc: 695; perl: 37; sed: 17; makefile: 15
file content (155 lines) | stat: -rw-r--r-- 4,020 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * Oracle Linux DTrace.
 * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

#include <unistd.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <link.h>
#include <sys/dtrace.h>
#include <sys/compiler.h>
#include <sys/ioctl.h>
#include <pthread.h>

#include <gelf.h>

#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/*
 * Users may set the following environment variables to affect the way
 * helper initialization takes place:
 *
 *	DTRACE_DOF_INIT_DEBUG		enable debugging output
 *	DTRACE_DOF_INIT_DISABLE		disable helper loading
 *	DTRACE_DOF_INIT_DEVNAME		set the path to the helper node
 */

static const char *devname = "/dev/dtrace/helper";

static int gen;			/* DOF helper generation */
static boolean_t dof_init_debug = B_FALSE;	/* From DTRACE_DOF_INIT_DEBUG */

static char *errmsg_open, *errmsg_ioctl_failed, *errmsg_ioctl_ok;

static void dtrace_dof_register(void);

static int
private_pthread_atfork(void (*prepare)(void), void (*parent)(void),
		       void (*child)(void))
{
  /* Sufficiently old glibc doesn't define pthread_atfork in libc, so we have to
     use an internal interface instead in order to not force all probe users to
     pull in -lpthread.  This internal interface is used by the pthread_atfork
     implementation in libc_nonshared.a in all glibcs new enough not to be
     affected by this problem, so there are no stable-ABI concerns here: the ABI
     is stable regardless.  */

#ifdef HAVE_PTHREAD_ATFORK
	return pthread_atfork(prepare, parent, child);
#else
	extern int __register_atfork(void (*prepare) (void),
				     void (*parent) (void),
				     void (*child) (void), void *dso_handle);
	extern void *__dso_handle _dt_weak_;

	return __register_atfork(prepare, parent, child, __dso_handle);
#endif
}

_dt_constructor_(dtrace_dof_init)
static void
dtrace_dof_init(void)
{
	const char *p;

	if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
		return;

	if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL)
		dof_init_debug = B_TRUE;

	if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
		devname = p;

	/*
	 * Prep error messages to avoid non-async-signal-safe printfs inside
	 * dtrace_dof_register().
	 */
	if (asprintf(&errmsg_ioctl_failed, "DRTI: Ioctl failed\n") < 0)
		errmsg_ioctl_failed = NULL;

	if (dof_init_debug) {
		if (asprintf(&errmsg_open, "DRTI: Failed to open helper device %s\n",
			     devname) < 0)
			errmsg_open = NULL;

		if (asprintf(&errmsg_ioctl_ok, "DRTI: Ioctl OK (gen %d)\n",
			     gen) < 0)
			errmsg_ioctl_ok = NULL;
	}

	dtrace_dof_register();
	private_pthread_atfork(NULL, NULL, dtrace_dof_register);
}

static void
dtrace_dof_register(void)
{
	int fd;

	if ((fd = open(devname, O_RDWR, O_CLOEXEC)) < 0) {
		if (dof_init_debug && errmsg_open)
			write(2, errmsg_open, strlen(errmsg_open));
		return;
	}

	gen = ioctl(fd, DTRACEHIOC_HASUSDT, (uintptr_t)dtrace_dof_init);
	if (gen == -1) {
		if (errmsg_ioctl_failed)
			write(2, errmsg_ioctl_failed,
			      strlen(errmsg_ioctl_failed));
		else {
			const char *ioctl_failed = "DRTI: Ioctl failed for DOF\n";
			write(2, ioctl_failed, strlen(ioctl_failed));
		}
	} else if (dof_init_debug && errmsg_ioctl_ok)
		write(2, errmsg_ioctl_ok, strlen(errmsg_ioctl_ok));

	close(fd);
}

_dt_destructor_(dtrace_dof_fini)
static void
dtrace_dof_fini(void)
{
	int fd;

	if ((fd = open(devname, O_RDWR | O_CLOEXEC)) < 0) {
		if (dof_init_debug)
			dprintf(2, "DRTI: Failed to open helper device %s\n",
				devname);
		return;
	}

	if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1)
		dprintf(2, "DRTI: Ioctl failed to remove DOF (gen %d)\n", gen);
	else if (dof_init_debug)
		dprintf(2, "DRTI: Ioctl removed DOF (gen %d)\n", gen);

	close(fd);

	free(errmsg_open);
	free(errmsg_ioctl_failed);
	free(errmsg_ioctl_ok);
	errmsg_open = NULL;
	errmsg_ioctl_failed = NULL;
	errmsg_ioctl_ok = NULL;
}