Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/cmd/ratrace.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
#include <thread.h>
5
 
6
enum {
7
	Stacksize	= 8*1024,
8
	Bufsize		= 8*1024,
9
};
10
 
11
Channel *out;
12
Channel *quit;
13
Channel *forkc;
14
int nread = 0;
15
 
16
typedef struct Str Str;
17
struct Str {
18
	char	*buf;
19
	int	len;
20
};
21
 
22
void
23
die(char *s)
24
{
25
	fprint(2, "%s\n", s);
26
	exits(s);
27
}
28
 
29
void
30
cwrite(int fd, char *path, char *cmd, int len)
31
{
32
	werrstr("");
33
	if (write(fd, cmd, len) < len) {
34
		fprint(2, "cwrite: %s: failed writing %d bytes: %r\n",
35
			path, len);
36
		sendp(quit, nil);
37
		threadexits(nil);
38
	}
39
}
40
 
41
Str *
42
newstr(void)
43
{
44
	Str *s;
45
 
46
	s = mallocz(sizeof(Str) + Bufsize, 1);
47
	if (s == nil)
48
		sysfatal("malloc");
49
	s->buf = (char *)&s[1];
50
	return s;
51
}
52
 
53
void
54
reader(void *v)
55
{
56
	int cfd, tfd, forking = 0, exiting, pid, newpid;
57
	char *ctl, *truss;
58
	Str *s;
59
	static char start[] = "start";
60
	static char waitstop[] = "waitstop";
61
 
62
	pid = (int)(uintptr)v;
63
	ctl = smprint("/proc/%d/ctl", pid);
64
	if ((cfd = open(ctl, OWRITE)) < 0)
65
		die(smprint("%s: %r", ctl));
66
	truss = smprint("/proc/%d/syscall", pid);
67
	if ((tfd = open(truss, OREAD)) < 0)
68
		die(smprint("%s: %r", truss));
69
 
70
	/* child was stopped by hang msg earlier */
71
	cwrite(cfd, ctl, waitstop, sizeof waitstop - 1);
72
 
73
	cwrite(cfd, ctl, "startsyscall", 12);
74
	s = newstr();
75
	exiting = 0;
76
	while((s->len = pread(tfd, s->buf, Bufsize - 1, 0)) >= 0){
77
		if (forking && s->buf[1] == '=' && s->buf[3] != '-') {
78
			forking = 0;
79
			newpid = strtol(&s->buf[3], 0, 0);
80
			sendp(forkc, (void*)newpid);
81
			procrfork(reader, (void*)newpid, Stacksize, 0);
82
		}
83
 
84
		/*
85
		 * There are three tests here and they (I hope) guarantee
86
		 * no false positives.
87
		 */
88
		if (strstr(s->buf, " Rfork") != nil) {
89
			char *a[8];
90
			char *rf;
91
 
92
			rf = strdup(s->buf);
93
         		if (tokenize(rf, a, 8) == 5 &&
94
			    strtoul(a[4], 0, 16) & RFPROC)
95
				forking = 1;
96
			free(rf);
97
		} else if (strstr(s->buf, " Exits") != nil)
98
			exiting = 1;
99
 
100
		sendp(out, s);	/* print line from /proc/$child/syscall */
101
		if (exiting) {
102
			s = newstr();
103
			strcpy(s->buf, "\n");
104
			sendp(out, s);
105
			break;
106
		}
107
 
108
		/* flush syscall trace buffer */
109
		cwrite(cfd, ctl, "startsyscall", 12);
110
		s = newstr();
111
	}
112
 
113
	sendp(quit, nil);
114
	threadexitsall(nil);
115
}
116
 
117
void
118
writer(void *)
119
{
120
	int newpid;
121
	Alt a[4];
122
	Str *s;
123
 
124
	a[0].op = CHANRCV;
125
	a[0].c = quit;
126
	a[0].v = nil;
127
	a[1].op = CHANRCV;
128
	a[1].c = out;
129
	a[1].v = &s;
130
	a[2].op = CHANRCV;
131
	a[2].c = forkc;
132
	a[2].v = &newpid;
133
	a[3].op = CHANEND;
134
 
135
	for(;;)
136
		switch(alt(a)){
137
		case 0:			/* quit */
138
			nread--;
139
			if(nread <= 0)
140
				goto done;
141
			break;
142
		case 1:			/* out */
143
			/* it's a nice null terminated thing */
144
			fprint(2, "%s", s->buf);
145
			free(s);
146
			break;
147
		case 2:			/* forkc */
148
			// procrfork(reader, (void*)newpid, Stacksize, 0);
149
			nread++;
150
			break;
151
		}
152
done:
153
	exits(nil);
154
}
155
 
156
void
157
usage(void)
158
{
159
	fprint(2, "Usage: ratrace [-c cmd [arg...]] | [pid]\n");
160
	exits("usage");
161
}
162
 
163
void
164
hang(void)
165
{
166
	int me;
167
	char *myctl;
168
	static char hang[] = "hang";
169
 
170
	myctl = smprint("/proc/%d/ctl", getpid());
171
	me = open(myctl, OWRITE);
172
	if (me < 0)
173
		sysfatal("can't open %s: %r", myctl);
174
	cwrite(me, myctl, hang, sizeof hang - 1);
175
	close(me);
176
	free(myctl);
177
}
178
 
179
void
180
threadmain(int argc, char **argv)
181
{
182
	int pid;
183
	char *cmd = nil;
184
	char **args = nil;
185
 
186
	/*
187
	 * don't bother with fancy arg processing, because it picks up options
188
	 * for the command you are starting.  Just check for -c as argv[1]
189
	 * and then take it from there.
190
	 */
191
	if (argc < 2)
192
		usage();
193
	while (argv[1][0] == '-') {
194
		switch(argv[1][1]) {
195
		case 'c':
196
			if (argc < 3)
197
				usage();
198
			cmd = strdup(argv[2]);
199
			args = &argv[2];
200
			break;
201
		default:
202
			usage();
203
		}
204
		++argv;
205
		--argc;
206
	}
207
 
208
	/* run a command? */
209
	if(cmd) {
210
		pid = fork();
211
		if (pid < 0)
212
			sysfatal("fork failed: %r");
213
		if(pid == 0) {
214
			hang();
215
			exec(cmd, args);
216
			if(cmd[0] != '/')
217
				exec(smprint("/bin/%s", cmd), args);
218
			sysfatal("exec %s failed: %r", cmd);
219
		}
220
	} else {
221
		if(argc != 2)
222
			usage();
223
		pid = atoi(argv[1]);
224
	}
225
 
226
	out   = chancreate(sizeof(char*), 0);
227
	quit  = chancreate(sizeof(char*), 0);
228
	forkc = chancreate(sizeof(ulong *), 0);
229
	nread++;
230
	procrfork(writer, nil, Stacksize, 0);
231
	reader((void*)pid);
232
}