xref: /minix/minix/usr.bin/trace/service/ipc.c (revision e1cdaee1)
1 /* This file is concerned with the IPC server, not with kernel-level IPC. */
2 
3 #include "inc.h"
4 
5 #include <sys/ipc.h>
6 #include <sys/shm.h>
7 #include <sys/sem.h>
8 
9 static void
10 put_key(struct trace_proc * proc, const char * name, key_t key)
11 {
12 
13 	if (!valuesonly && key == IPC_PRIVATE)
14 		put_field(proc, name, "IPC_PRIVATE");
15 	else
16 		put_value(proc, name, "%ld", key);
17 }
18 
19 static const struct flags ipcget_flags[] = {
20 	FLAG(IPC_CREAT),
21 	FLAG(IPC_EXCL),
22 };
23 
24 static int
25 ipc_shmget_out(struct trace_proc * proc, const message * m_out)
26 {
27 
28 	put_key(proc, "key", m_out->m_lc_ipc_shmget.key);
29 	put_value(proc, "size", "%zu", m_out->m_lc_ipc_shmget.size);
30 	put_flags(proc, "shmflg", ipcget_flags, COUNT(ipcget_flags), "0%o",
31 	    m_out->m_lc_ipc_shmget.flag);
32 
33 	return CT_DONE;
34 }
35 
36 static void
37 ipc_shmget_in(struct trace_proc * proc, const message * __unused m_out,
38 	const message * m_in, int failed)
39 {
40 
41 	if (!failed)
42 		put_value(proc, NULL, "%d", m_in->m_lc_ipc_shmget.retid);
43 	else
44 		put_result(proc);
45 }
46 
47 static const struct flags shmat_flags[] = {
48 	FLAG(SHM_RDONLY),
49 	FLAG(SHM_RND),
50 };
51 
52 static int
53 ipc_shmat_out(struct trace_proc * proc, const message * m_out)
54 {
55 
56 	put_value(proc, "shmid", "%d", m_out->m_lc_ipc_shmat.id);
57 	put_ptr(proc, "shmaddr", (vir_bytes)m_out->m_lc_ipc_shmat.addr);
58 	put_flags(proc, "shmflg", shmat_flags, COUNT(shmat_flags), "0x%x",
59 	    m_out->m_lc_ipc_shmat.flag);
60 
61 	return CT_DONE;
62 }
63 
64 static void
65 ipc_shmat_in(struct trace_proc * proc, const message * __unused m_out,
66 	const message * m_in, int failed)
67 {
68 
69 	if (!failed)
70 		put_ptr(proc, NULL, (vir_bytes)m_in->m_lc_ipc_shmat.retaddr);
71 	else
72 		put_result(proc);
73 }
74 
75 static int
76 ipc_shmdt_out(struct trace_proc * proc, const message * m_out)
77 {
78 
79 	put_ptr(proc, "shmaddr", (vir_bytes)m_out->m_lc_ipc_shmdt.addr);
80 
81 	return CT_DONE;
82 }
83 
84 static void
85 put_shmctl_cmd(struct trace_proc * proc, const char * name, int cmd)
86 {
87 	const char *text = NULL;
88 
89 	if (!valuesonly) {
90 		switch (cmd) {
91 		TEXT(IPC_RMID);
92 		TEXT(IPC_SET);
93 		TEXT(IPC_STAT);
94 		TEXT(SHM_STAT);
95 		TEXT(SHM_INFO);
96 		TEXT(IPC_INFO);
97 		}
98 	}
99 
100 	if (text != NULL)
101 		put_field(proc, name, text);
102 	else
103 		put_value(proc, name, "%d", cmd);
104 }
105 
106 static const struct flags shm_mode_flags[] = {
107 	FLAG(SHM_DEST),
108 	FLAG(SHM_LOCKED),
109 };
110 
111 static void
112 put_struct_shmid_ds(struct trace_proc * proc, const char * name, int flags,
113 	vir_bytes addr)
114 {
115 	struct shmid_ds buf;
116 	int set;
117 
118 	if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
119 		return;
120 
121 	/* Is this an IPC_SET call?  Then print a small subset of fields.. */
122 	set = (flags & PF_ALT);
123 
124 	put_open(proc, "shm_perm", 0, "{", ", ");
125 
126 	put_value(proc, "uid", "%u", buf.shm_perm.uid);
127 	put_value(proc, "gid", "%u", buf.shm_perm.gid);
128 	if (!set && verbose > 0) {
129 		put_value(proc, "cuid", "%u", buf.shm_perm.cuid);
130 		put_value(proc, "cgid", "%u", buf.shm_perm.cgid);
131 	}
132 	put_flags(proc, "mode", shm_mode_flags, COUNT(shm_mode_flags),
133 	    "0%03o", buf.shm_perm.mode);
134 
135 	put_close(proc, "}");
136 
137 	if (!set) {
138 		put_value(proc, "shm_segsz", "%zu", buf.shm_segsz);
139 		if (verbose > 0) {
140 			put_value(proc, "shm_lpid", "%d", buf.shm_lpid);
141 			put_value(proc, "shm_cpid", "%d", buf.shm_cpid);
142 			put_time(proc, "shm_atime", buf.shm_atime);
143 			put_time(proc, "shm_dtime", buf.shm_dtime);
144 			put_time(proc, "shm_ctime", buf.shm_ctime);
145 		}
146 		put_value(proc, "shm_nattch", "%u", buf.shm_nattch);
147 	}
148 
149 	put_close_struct(proc, set || verbose > 0);
150 }
151 
152 static int
153 ipc_shmctl_out(struct trace_proc * proc, const message * m_out)
154 {
155 
156 	put_value(proc, "shmid", "%d", m_out->m_lc_ipc_shmctl.id);
157 	put_shmctl_cmd(proc, "cmd", m_out->m_lc_ipc_shmctl.cmd);
158 
159 	/* TODO: add support for the IPC_INFO and SHM_INFO structures.. */
160 	switch (m_out->m_lc_ipc_shmctl.cmd) {
161 	case IPC_STAT:
162 	case SHM_STAT:
163 		return CT_NOTDONE;
164 
165 	case IPC_SET:
166 		put_struct_shmid_ds(proc, "buf", PF_ALT,
167 		    (vir_bytes)m_out->m_lc_ipc_shmctl.buf);
168 
169 		return CT_DONE;
170 
171 	default:
172 		put_ptr(proc, "buf", (vir_bytes)m_out->m_lc_ipc_shmctl.buf);
173 
174 		return CT_DONE;
175 	}
176 }
177 
178 static void
179 ipc_shmctl_in(struct trace_proc * proc, const message * m_out,
180 	const message * m_in, int failed)
181 {
182 
183 	switch (m_out->m_lc_ipc_shmctl.cmd) {
184 	case IPC_STAT:
185 	case SHM_STAT:
186 		put_struct_shmid_ds(proc, "buf", failed,
187 		    (vir_bytes)m_out->m_lc_ipc_shmctl.buf);
188 		put_equals(proc);
189 
190 		break;
191 	}
192 
193 	if (!failed) {
194 		switch (m_out->m_lc_ipc_shmctl.cmd) {
195 		case SHM_INFO:
196 		case SHM_STAT:
197 		case IPC_INFO:
198 			put_value(proc, NULL, "%d", m_in->m_lc_ipc_shmctl.ret);
199 
200 			return;
201 		}
202 	}
203 
204 	put_result(proc);
205 }
206 
207 static int
208 ipc_semget_out(struct trace_proc * proc, const message * m_out)
209 {
210 
211 	put_key(proc, "key", m_out->m_lc_ipc_semget.key);
212 	put_value(proc, "nsems", "%d", m_out->m_lc_ipc_semget.nr);
213 	put_flags(proc, "semflg", ipcget_flags, COUNT(ipcget_flags), "0%o",
214 	    m_out->m_lc_ipc_semget.flag);
215 
216 	return CT_DONE;
217 }
218 
219 static void
220 ipc_semget_in(struct trace_proc * proc, const message * __unused m_out,
221 	const message * m_in, int failed)
222 {
223 
224 	if (!failed)
225 		put_value(proc, NULL, "%d", m_in->m_lc_ipc_semget.retid);
226 	else
227 		put_result(proc);
228 }
229 
230 static void
231 put_semctl_cmd(struct trace_proc * proc, const char * name, int cmd)
232 {
233 	const char *text = NULL;
234 
235 	if (!valuesonly) {
236 		switch (cmd) {
237 		TEXT(IPC_RMID);
238 		TEXT(IPC_SET);
239 		TEXT(IPC_STAT);
240 		TEXT(GETNCNT);
241 		TEXT(GETPID);
242 		TEXT(GETVAL);
243 		TEXT(GETALL);
244 		TEXT(GETZCNT);
245 		TEXT(SETVAL);
246 		TEXT(SETALL);
247 		TEXT(SEM_STAT);
248 		TEXT(SEM_INFO);
249 		TEXT(IPC_INFO);
250 		}
251 	}
252 
253 	if (text != NULL)
254 		put_field(proc, name, text);
255 	else
256 		put_value(proc, name, "%d", cmd);
257 }
258 
259 static void
260 put_struct_semid_ds(struct trace_proc * proc, const char * name, int flags,
261 	vir_bytes addr)
262 {
263 	struct semid_ds buf;
264 	int set;
265 
266 	if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
267 		return;
268 
269 	/* Is this an IPC_SET call?  Then print a small subset of fields.. */
270 	set = (flags & PF_ALT);
271 
272 	put_open(proc, "sem_perm", 0, "{", ", ");
273 
274 	put_value(proc, "uid", "%u", buf.sem_perm.uid);
275 	put_value(proc, "gid", "%u", buf.sem_perm.gid);
276 	if (!set && verbose > 0) {
277 		put_value(proc, "cuid", "%u", buf.sem_perm.cuid);
278 		put_value(proc, "cgid", "%u", buf.sem_perm.cgid);
279 	}
280 	put_value(proc, "mode", "0%03o", buf.sem_perm.mode);
281 
282 	put_close(proc, "}");
283 
284 	if (!set) {
285 		if (verbose > 0) {
286 			put_time(proc, "sem_otime", buf.sem_otime);
287 			put_time(proc, "sem_ctime", buf.sem_ctime);
288 		}
289 		put_value(proc, "sem_nsems", "%u", buf.sem_nsems);
290 	}
291 
292 	put_close_struct(proc, set || verbose > 0);
293 }
294 
295 
296 static int
297 ipc_semctl_out(struct trace_proc * proc, const message * m_out)
298 {
299 
300 	put_value(proc, "semid", "%d", m_out->m_lc_ipc_semctl.id);
301 	put_value(proc, "semnum", "%d", m_out->m_lc_ipc_semctl.num);
302 	put_semctl_cmd(proc, "cmd", m_out->m_lc_ipc_semctl.cmd);
303 
304 	/* TODO: add support for the IPC_INFO and SEM_INFO structures.. */
305 	switch (m_out->m_lc_ipc_semctl.cmd) {
306 	case IPC_STAT:
307 	case SEM_STAT:
308 		return CT_NOTDONE;
309 
310 	case IPC_SET:
311 		put_struct_semid_ds(proc, "buf", PF_ALT,
312 		    (vir_bytes)m_out->m_lc_ipc_semctl.opt);
313 
314 		return CT_DONE;
315 
316 	case IPC_INFO:
317 	case SEM_INFO:
318 		put_ptr(proc, "buf", (vir_bytes)m_out->m_lc_ipc_semctl.opt);
319 
320 		return CT_DONE;
321 
322 	case GETALL:
323 	case SETALL:
324 		put_ptr(proc, "array", (vir_bytes)m_out->m_lc_ipc_semctl.opt);
325 
326 		return CT_DONE;
327 
328 	case SETVAL:
329 		put_value(proc, "val", "%lu", m_out->m_lc_ipc_semctl.opt);
330 
331 		return CT_DONE;
332 
333 	default:
334 		return CT_DONE;
335 	}
336 }
337 
338 static void
339 ipc_semctl_in(struct trace_proc * proc, const message * m_out,
340 	const message * m_in, int failed)
341 {
342 
343 	switch (m_out->m_lc_ipc_semctl.cmd) {
344 	case IPC_STAT:
345 	case SEM_STAT:
346 		put_struct_semid_ds(proc, "buf", failed,
347 		    (vir_bytes)m_out->m_lc_ipc_semctl.opt);
348 		put_equals(proc);
349 
350 		break;
351 	}
352 
353 	if (!failed) {
354 		switch (m_out->m_lc_ipc_semctl.cmd) {
355 		case GETNCNT:
356 		case GETPID:
357 		case GETVAL:
358 		case GETZCNT:
359 		case SEM_INFO:
360 		case SEM_STAT:
361 		case IPC_INFO:
362 			put_value(proc, NULL, "%d", m_in->m_lc_ipc_semctl.ret);
363 			return;
364 		}
365 	}
366 	put_result(proc);
367 }
368 
369 static const struct flags sem_flags[] = {
370 	FLAG(IPC_NOWAIT),
371 	FLAG(SEM_UNDO),
372 };
373 
374 static void
375 put_struct_sembuf(struct trace_proc * proc, const char * name, int flags,
376 	vir_bytes addr)
377 {
378 	struct sembuf buf;
379 	int all;
380 
381 	if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
382 		return;
383 
384 	all = FALSE;
385 	put_value(proc, "sem_num", "%u", buf.sem_num);
386 	put_value(proc, "sem_op", "%d", buf.sem_op);
387 	if (verbose > 0 || (buf.sem_flg & ~SEM_UNDO) != 0) {
388 		put_flags(proc, "sem_flg", sem_flags, COUNT(sem_flags), "0x%x",
389 		   buf.sem_flg);
390 		all = TRUE;
391 	}
392 
393 	put_close_struct(proc, all);
394 }
395 
396 static void
397 put_sembuf_array(struct trace_proc * proc, const char * name, vir_bytes addr,
398 	size_t count)
399 {
400 	struct sembuf buf[SEMOPM]; /* about 600 bytes, so OK for the stack */
401 	size_t i;
402 
403 	if (valuesonly > 1 || count > SEMOPM ||
404 	    mem_get_data(proc->pid, addr, &buf, count * sizeof(buf[0])) != 0) {
405 		put_ptr(proc, name, addr);
406 
407 		return;
408 	}
409 
410 	put_open(proc, name, PF_NONAME, "[", ", ");
411 	for (i = 0; i < count; i++)
412 		put_struct_sembuf(proc, NULL, PF_LOCADDR, (vir_bytes)&buf[i]);
413 	put_close(proc, "]");
414 }
415 
416 static int
417 ipc_semop_out(struct trace_proc * proc, const message * m_out)
418 {
419 
420 	put_value(proc, "semid", "%d", m_out->m_lc_ipc_semop.id);
421 	put_sembuf_array(proc, "sops", (vir_bytes)m_out->m_lc_ipc_semop.ops,
422 	    m_out->m_lc_ipc_semop.size);
423 	put_value(proc, "nsops", "%u", m_out->m_lc_ipc_semop.size);
424 
425 	return CT_DONE;
426 }
427 
428 #define IPC_CALL(c) [((IPC_ ## c) - IPC_BASE)]
429 
430 static const struct call_handler ipc_map[] = {
431 	IPC_CALL(SHMGET) = HANDLER("shmget", ipc_shmget_out, ipc_shmget_in),
432 	IPC_CALL(SHMAT) = HANDLER("shmat", ipc_shmat_out, ipc_shmat_in),
433 	IPC_CALL(SHMDT) = HANDLER("shmdt", ipc_shmdt_out, default_in),
434 	IPC_CALL(SHMCTL) = HANDLER("shmctl", ipc_shmctl_out, ipc_shmctl_in),
435 	IPC_CALL(SEMGET) = HANDLER("semget", ipc_semget_out, ipc_semget_in),
436 	IPC_CALL(SEMCTL) = HANDLER("semctl", ipc_semctl_out, ipc_semctl_in),
437 	IPC_CALL(SEMOP) = HANDLER("semop", ipc_semop_out, default_in),
438 };
439 
440 const struct calls ipc_calls = {
441 	.endpt = ANY,
442 	.base = IPC_BASE,
443 	.map = ipc_map,
444 	.count = COUNT(ipc_map)
445 };
446