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