1 /* ProcFS - pid.c - by Alen Stojanov and David van Moolenbroek */
8 #define S_FRAME_SIZE 4096 /* use malloc if larger than this */
9 static char s_frame
[S_FRAME_SIZE
]; /* static storage for process frame */
10 static char *frame
; /* pointer to process frame buffer */
12 static void pid_psinfo(int slot
);
13 static void pid_cmdline(int slot
);
14 static void pid_environ(int slot
);
15 static void pid_map(int slot
);
17 /* The files that are dynamically created in each PID directory. The data field
18 * contains each file's read function. Subdirectories are not yet supported.
20 struct file pid_files
[] = {
21 { "psinfo", REG_ALL_MODE
, (data_t
) pid_psinfo
},
22 { "cmdline", REG_ALL_MODE
, (data_t
) pid_cmdline
},
23 { "environ", REG_ALL_MODE
, (data_t
) pid_environ
},
24 { "map", REG_ALL_MODE
, (data_t
) pid_map
},
25 { NULL
, 0, (data_t
) NULL
}
28 /*===========================================================================*
30 *===========================================================================*/
31 static int is_zombie(int slot
)
33 /* Is the given slot a zombie process?
36 return (slot
>= NR_TASKS
&&
37 (mproc
[slot
- NR_TASKS
].mp_flags
& (TRACE_ZOMBIE
| ZOMBIE
)));
40 /*===========================================================================*
42 *===========================================================================*/
43 static void pid_psinfo(int i
)
45 /* Print information used by ps(1) and top(1).
47 int pi
, task
, state
, type
, p_state
, f_state
;
48 char name
[PROC_NAME_LEN
+1], *p
;
49 struct vm_usage_info vui
;
53 task
= proc
[i
].p_nr
< 0;
55 /* Get the name of the process. Spaces would mess up the format.. */
56 if (task
|| mproc
[i
].mp_name
[0] == 0)
57 strncpy(name
, proc
[i
].p_name
, sizeof(name
) - 1);
59 strncpy(name
, mproc
[pi
].mp_name
, sizeof(name
) - 1);
60 name
[sizeof(name
) - 1] = 0;
61 if ((p
= strchr(name
, ' ')) != NULL
)
64 /* Get the type of the process. */
67 else if (mproc
[i
].mp_flags
& PRIV_PROC
)
72 /* Get the state of the process. */
75 state
= STATE_ZOMBIE
; /* zombie */
76 else if (mproc
[pi
].mp_flags
& STOPPED
)
77 state
= STATE_STOP
; /* stopped (traced) */
78 else if (proc
[i
].p_rts_flags
== 0)
79 state
= STATE_RUN
; /* in run-queue */
80 else if (fp_is_blocked(&fproc
[pi
]) ||
81 (mproc
[pi
].mp_flags
& (WAITING
| PAUSED
| SIGSUSPENDED
)))
82 state
= STATE_SLEEP
; /* sleeping */
84 state
= STATE_WAIT
; /* waiting */
86 if (proc
[i
].p_rts_flags
== 0)
87 state
= STATE_RUN
; /* in run-queue */
89 state
= STATE_WAIT
; /* other i.e. waiting */
92 /* We assume that even if a process has become a zombie, its kernel
93 * proc entry still contains the old (but valid) information. Currently
94 * this is true, but in the future we may have to filter some fields.
96 buf_printf("%d %c %d %s %c %d %d %lu %lu %lu %lu",
97 PSINFO_VERSION
, /* information version */
98 type
, /* process type */
99 (int) proc
[i
].p_endpoint
, /* process endpoint */
100 name
, /* process name */
101 state
, /* process state letter */
102 (int) P_BLOCKEDON(&proc
[i
]), /* endpt blocked on, or NONE */
103 (int) proc
[i
].p_priority
, /* process priority */
104 (long) proc
[i
].p_user_time
, /* user time */
105 (long) proc
[i
].p_sys_time
, /* system time */
106 ex64hi(proc
[i
].p_cycles
), /* execution cycles */
107 ex64lo(proc
[i
].p_cycles
)
110 memset(&vui
, 0, sizeof(vui
));
113 /* We don't care if this fails. */
114 (void) vm_info_usage(proc
[i
].p_endpoint
, &vui
);
117 /* If the process is not a kernel task, we add some extra info. */
119 if (mproc
[pi
].mp_flags
& PAUSED
)
120 p_state
= PSTATE_PAUSED
;
121 else if (mproc
[pi
].mp_flags
& WAITING
)
122 p_state
= PSTATE_WAITING
;
123 else if (mproc
[pi
].mp_flags
& SIGSUSPENDED
)
124 p_state
= PSTATE_SIGSUSP
;
128 if (mproc
[pi
].mp_parent
== pi
)
131 ppid
= mproc
[mproc
[pi
].mp_parent
].mp_pid
;
133 switch (fproc
[pi
].fp_blocked_on
) {
134 case FP_BLOCKED_ON_NONE
: f_state
= FSTATE_NONE
; break;
135 case FP_BLOCKED_ON_PIPE
: f_state
= FSTATE_PIPE
; break;
136 case FP_BLOCKED_ON_LOCK
: f_state
= FSTATE_LOCK
; break;
137 case FP_BLOCKED_ON_POPEN
: f_state
= FSTATE_POPEN
; break;
138 case FP_BLOCKED_ON_SELECT
: f_state
= FSTATE_SELECT
; break;
139 case FP_BLOCKED_ON_DOPEN
: f_state
= FSTATE_DOPEN
; break;
140 case FP_BLOCKED_ON_OTHER
: f_state
= FSTATE_TASK
; break;
141 default: f_state
= FSTATE_UNKNOWN
;
144 buf_printf(" %lu %lu %lu %c %d %u %u %u %d %c %d %u",
145 vui
.vui_total
, /* total memory */
146 vui
.vui_common
, /* common memory */
147 vui
.vui_shared
, /* shared memory */
148 p_state
, /* sleep state */
149 ppid
, /* parent PID */
150 mproc
[pi
].mp_realuid
, /* real UID */
151 mproc
[pi
].mp_effuid
, /* effective UID */
152 mproc
[pi
].mp_procgrp
, /* process group */
153 mproc
[pi
].mp_nice
, /* nice value */
154 f_state
, /* VFS block state */
155 (int) (fproc
[pi
].fp_blocked_on
== FP_BLOCKED_ON_OTHER
)
156 ? fproc
[pi
].fp_task
: NONE
, /* block proc */
157 fproc
[pi
].fp_tty
/* controlling tty */
161 /* always add kernel cycles */
162 buf_printf(" %lu %lu %lu %lu",
163 ex64hi(proc
[i
].p_kipc_cycles
),
164 ex64lo(proc
[i
].p_kipc_cycles
),
165 ex64hi(proc
[i
].p_kcall_cycles
),
166 ex64lo(proc
[i
].p_kcall_cycles
));
168 /* add total memory for tasks at the end */
169 if(task
) buf_printf(" %lu", vui
.vui_total
);
171 /* Newline at the end of the file. */
175 /*===========================================================================*
177 *===========================================================================*/
178 static void put_frame(void)
180 /* If we allocated memory dynamically during a call to get_frame(),
184 if (frame
!= s_frame
)
188 /*===========================================================================*
190 *===========================================================================*/
191 static int get_frame(int slot
, vir_bytes
*basep
, vir_bytes
*sizep
,
194 /* Get the execution frame from the top of the given process's stack.
195 * It may be very large, in which case we temporarily allocate memory
196 * for it (up to a certain size).
198 vir_bytes base
, size
;
201 if (proc
[slot
].p_nr
< 0 || is_zombie(slot
))
204 /* Get the frame base address and size. Limit the size to whatever we
205 * can handle. If our static buffer is not sufficiently large to store
206 * the entire frame, allocate memory dynamically. It is then later
207 * freed by put_frame().
209 base
= mproc
[slot
- NR_TASKS
].mp_frame_addr
;
210 size
= mproc
[slot
- NR_TASKS
].mp_frame_len
;
212 if (size
< sizeof(size_t)) return FALSE
;
214 if (size
> ARG_MAX
) size
= ARG_MAX
;
216 if (size
> sizeof(s_frame
)) {
217 frame
= malloc(size
);
222 else frame
= s_frame
;
224 /* Copy in the complete process frame. */
225 if (sys_datacopy(proc
[slot
].p_endpoint
, base
,
226 SELF
, (vir_bytes
) frame
, (phys_bytes
) size
) != OK
) {
232 frame
[size
] = 0; /* terminate any last string */
234 nargs
= * (size_t *) frame
;
235 if (nargs
< 1 || sizeof(size_t) + sizeof(char *) * (nargs
+ 1) > size
) {
245 /* The caller now has to called put_frame() to clean up. */
249 /*===========================================================================*
251 *===========================================================================*/
252 static void pid_cmdline(int slot
)
254 /* Dump the process's command line as it is contained in the process
255 * itself. Each argument is terminated with a null character.
257 vir_bytes base
, size
, ptr
;
258 size_t i
, len
, nargs
;
261 if (!get_frame(slot
, &base
, &size
, &nargs
))
264 argv
= (char **) &frame
[sizeof(size_t)];
266 for (i
= 0; i
< nargs
; i
++) {
267 ptr
= (vir_bytes
) argv
[i
] - base
;
269 /* Check for bad pointers. */
270 if ((long) ptr
< 0L || ptr
>= size
)
273 len
= strlen(&frame
[ptr
]) + 1;
275 buf_append(&frame
[ptr
], len
);
281 /*===========================================================================*
283 *===========================================================================*/
284 static void pid_environ(int slot
)
286 /* Dump the process's initial environment as it is contained in the
287 * process itself. Each entry is terminated with a null character.
289 vir_bytes base
, size
, ptr
;
290 size_t nargs
, off
, len
;
293 if (!get_frame(slot
, &base
, &size
, &nargs
))
296 off
= sizeof(size_t) + sizeof(char *) * (nargs
+ 1);
297 envp
= (char **) &frame
[off
];
300 /* Make sure there is no buffer overrun. */
301 if (off
+ sizeof(char *) > size
)
304 ptr
= (vir_bytes
) *envp
;
306 /* Stop at the terminating NULL pointer. */
312 /* Check for bad pointers. */
313 if ((long) ptr
< 0L || ptr
>= size
)
316 len
= strlen(&frame
[ptr
]) + 1;
318 buf_append(&frame
[ptr
], len
);
320 off
+= sizeof(char *);
327 /*===========================================================================*
329 *===========================================================================*/
330 static int dump_regions(int slot
)
332 /* Print the virtual memory regions of a process.
334 struct vm_region_info vri
[MAX_VRI_COUNT
];
342 r
= vm_info_region(proc
[slot
].p_endpoint
, vri
, MAX_VRI_COUNT
,
351 for (i
= 0; i
< r
; i
++) {
352 buf_printf("%08lx-%08lx %c%c%c\n",
353 vri
[i
].vri_addr
, vri
[i
].vri_addr
+ vri
[i
].vri_length
,
354 (vri
[i
].vri_prot
& PROT_READ
) ? 'r' : '-',
355 (vri
[i
].vri_prot
& PROT_WRITE
) ? 'w' : '-',
356 (vri
[i
].vri_prot
& PROT_EXEC
) ? 'x' : '-');
360 } while (r
== MAX_VRI_COUNT
);
365 /*===========================================================================*
367 *===========================================================================*/
368 static void pid_map(int slot
)
370 /* Print a memory map of the process. Obtain the information from VM if
371 * possible; otherwise fall back on segments from the kernel.
374 /* Zombies have no memory. */
378 /* Kernel tasks also have no memory. */
379 if (proc
[slot
].p_nr
>= 0) {
380 if (dump_regions(slot
) != 0)