xref: /minix3/minix/kernel/debug.c (revision 9624407e7addfd8b88486acfe3a0e056e2b92ee3)
1433d6423SLionel Sambuc /* This file implements kernel debugging functionality that is not included
2433d6423SLionel Sambuc  * in the standard kernel. Available functionality includes timing of lock
3433d6423SLionel Sambuc  * functions and sanity checking of the scheduling queues.
4433d6423SLionel Sambuc  */
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include "kernel/kernel.h"
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc #include <minix/callnr.h>
9433d6423SLionel Sambuc #include <minix/u64.h>
10433d6423SLionel Sambuc #include <limits.h>
11433d6423SLionel Sambuc #include <string.h>
12433d6423SLionel Sambuc #include <assert.h>
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #define MAX_LOOP (NR_PROCS + NR_TASKS)
15433d6423SLionel Sambuc 
runqueues_ok_cpu(unsigned cpu)16433d6423SLionel Sambuc int runqueues_ok_cpu(unsigned cpu)
17433d6423SLionel Sambuc {
18433d6423SLionel Sambuc   int q, l = 0;
19433d6423SLionel Sambuc   register struct proc *xp;
20433d6423SLionel Sambuc   struct proc **rdy_head, **rdy_tail;
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc   rdy_head = get_cpu_var(cpu, run_q_head);
23433d6423SLionel Sambuc   rdy_tail = get_cpu_var(cpu, run_q_tail);
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc   for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) {
26433d6423SLionel Sambuc 	xp->p_found = 0;
27433d6423SLionel Sambuc 	if (l++ > MAX_LOOP) panic("check error");
28433d6423SLionel Sambuc   }
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc   for (q=l=0; q < NR_SCHED_QUEUES; q++) {
31433d6423SLionel Sambuc     if (rdy_head[q] && !rdy_tail[q]) {
32433d6423SLionel Sambuc 	printf("head but no tail in %d\n", q);
33433d6423SLionel Sambuc 	return 0;
34433d6423SLionel Sambuc     }
35433d6423SLionel Sambuc     if (!rdy_head[q] && rdy_tail[q]) {
36433d6423SLionel Sambuc 	printf("tail but no head in %d\n", q);
37433d6423SLionel Sambuc 	return 0;
38433d6423SLionel Sambuc     }
39433d6423SLionel Sambuc     if (rdy_tail[q] && rdy_tail[q]->p_nextready) {
40433d6423SLionel Sambuc 	printf("tail and tail->next not null in %d\n", q);
41433d6423SLionel Sambuc 	return 0;
42433d6423SLionel Sambuc     }
43433d6423SLionel Sambuc     for(xp = rdy_head[q]; xp; xp = xp->p_nextready) {
44433d6423SLionel Sambuc 	const vir_bytes vxp = (vir_bytes) xp;
45433d6423SLionel Sambuc 	vir_bytes dxp;
46433d6423SLionel Sambuc 	if(vxp < (vir_bytes) BEG_PROC_ADDR || vxp >= (vir_bytes) END_PROC_ADDR) {
47433d6423SLionel Sambuc   		printf("xp out of range\n");
48433d6423SLionel Sambuc 		return 0;
49433d6423SLionel Sambuc 	}
50433d6423SLionel Sambuc 	dxp = vxp - (vir_bytes) BEG_PROC_ADDR;
51433d6423SLionel Sambuc 	if(dxp % sizeof(struct proc)) {
52433d6423SLionel Sambuc   		printf("xp not a real pointer");
53433d6423SLionel Sambuc 		return 0;
54433d6423SLionel Sambuc 	}
55433d6423SLionel Sambuc 	if(!proc_ptr_ok(xp)) {
56433d6423SLionel Sambuc   		printf("xp bogus pointer");
57433d6423SLionel Sambuc 		return 0;
58433d6423SLionel Sambuc 	}
59433d6423SLionel Sambuc 	if (RTS_ISSET(xp, RTS_SLOT_FREE)) {
60433d6423SLionel Sambuc 		printf("scheduling error: dead proc q %d %d\n",
61433d6423SLionel Sambuc 			q, xp->p_endpoint);
62433d6423SLionel Sambuc 		return 0;
63433d6423SLionel Sambuc 	}
64433d6423SLionel Sambuc         if (!proc_is_runnable(xp)) {
65433d6423SLionel Sambuc 		printf("scheduling error: unready on runq %d proc %d\n",
66433d6423SLionel Sambuc 			q, xp->p_nr);
67433d6423SLionel Sambuc 		return 0;
68433d6423SLionel Sambuc         }
69433d6423SLionel Sambuc         if (xp->p_priority != q) {
70433d6423SLionel Sambuc 		printf("scheduling error: wrong priority q %d proc %d ep %d name %s\n",
71433d6423SLionel Sambuc 			q, xp->p_nr, xp->p_endpoint, xp->p_name);
72433d6423SLionel Sambuc 		return 0;
73433d6423SLionel Sambuc 	}
74433d6423SLionel Sambuc 	if (xp->p_found) {
75433d6423SLionel Sambuc 		printf("scheduling error: double sched q %d proc %d\n",
76433d6423SLionel Sambuc 			q, xp->p_nr);
77433d6423SLionel Sambuc 		return 0;
78433d6423SLionel Sambuc 	}
79433d6423SLionel Sambuc 	xp->p_found = 1;
80433d6423SLionel Sambuc 	if (!xp->p_nextready && rdy_tail[q] != xp) {
81433d6423SLionel Sambuc 		printf("sched err: last element not tail q %d proc %d\n",
82433d6423SLionel Sambuc 			q, xp->p_nr);
83433d6423SLionel Sambuc 		return 0;
84433d6423SLionel Sambuc 	}
85433d6423SLionel Sambuc 	if (l++ > MAX_LOOP) {
86433d6423SLionel Sambuc 		printf("loop in schedule queue?");
87433d6423SLionel Sambuc 		return 0;
88433d6423SLionel Sambuc 	}
89433d6423SLionel Sambuc     }
90433d6423SLionel Sambuc   }
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc   for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) {
93433d6423SLionel Sambuc 	if(!proc_ptr_ok(xp)) {
94433d6423SLionel Sambuc 		printf("xp bogus pointer in proc table\n");
95433d6423SLionel Sambuc 		return 0;
96433d6423SLionel Sambuc 	}
97433d6423SLionel Sambuc 	if (isemptyp(xp))
98433d6423SLionel Sambuc 		continue;
99433d6423SLionel Sambuc 	if(proc_is_runnable(xp) && !xp->p_found) {
100433d6423SLionel Sambuc 		printf("sched error: ready proc %d not on queue\n", xp->p_nr);
101433d6423SLionel Sambuc 		return 0;
102433d6423SLionel Sambuc 	}
103433d6423SLionel Sambuc   }
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc   /* All is ok. */
106433d6423SLionel Sambuc   return 1;
107433d6423SLionel Sambuc }
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc #ifdef CONFIG_SMP
runqueues_ok_all(void)110433d6423SLionel Sambuc static int runqueues_ok_all(void)
111433d6423SLionel Sambuc {
112433d6423SLionel Sambuc 	unsigned c;
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc 	for (c = 0 ; c < ncpus; c++) {
115433d6423SLionel Sambuc 		if (!runqueues_ok_cpu(c))
116433d6423SLionel Sambuc 			return 0;
117433d6423SLionel Sambuc 	}
118433d6423SLionel Sambuc 	return 1;
119433d6423SLionel Sambuc }
120433d6423SLionel Sambuc 
runqueues_ok(void)121433d6423SLionel Sambuc int runqueues_ok(void)
122433d6423SLionel Sambuc {
123433d6423SLionel Sambuc 	return runqueues_ok_all();
124433d6423SLionel Sambuc }
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc #else
127433d6423SLionel Sambuc 
runqueues_ok(void)128433d6423SLionel Sambuc int runqueues_ok(void)
129433d6423SLionel Sambuc {
130433d6423SLionel Sambuc 	return runqueues_ok_cpu(0);
131433d6423SLionel Sambuc }
132433d6423SLionel Sambuc 
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc #endif
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc char *
rtsflagstr(const u32_t flags)137433d6423SLionel Sambuc rtsflagstr(const u32_t flags)
138433d6423SLionel Sambuc {
139433d6423SLionel Sambuc 	static char str[100];
140433d6423SLionel Sambuc 	str[0] = '\0';
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc #define FLAG(n) if(flags & n) { strlcat(str, #n " ", sizeof(str)); }
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc 	FLAG(RTS_SLOT_FREE);
145433d6423SLionel Sambuc 	FLAG(RTS_PROC_STOP);
146433d6423SLionel Sambuc 	FLAG(RTS_SENDING);
147433d6423SLionel Sambuc 	FLAG(RTS_RECEIVING);
148433d6423SLionel Sambuc 	FLAG(RTS_SIGNALED);
149433d6423SLionel Sambuc 	FLAG(RTS_SIG_PENDING);
150433d6423SLionel Sambuc 	FLAG(RTS_P_STOP);
151433d6423SLionel Sambuc 	FLAG(RTS_NO_PRIV);
152433d6423SLionel Sambuc 	FLAG(RTS_NO_ENDPOINT);
153433d6423SLionel Sambuc 	FLAG(RTS_VMINHIBIT);
154433d6423SLionel Sambuc 	FLAG(RTS_PAGEFAULT);
155433d6423SLionel Sambuc 	FLAG(RTS_VMREQUEST);
156433d6423SLionel Sambuc 	FLAG(RTS_VMREQTARGET);
157433d6423SLionel Sambuc 	FLAG(RTS_PREEMPTED);
158433d6423SLionel Sambuc 	FLAG(RTS_NO_QUANTUM);
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc 	return str;
161433d6423SLionel Sambuc }
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc char *
miscflagstr(const u32_t flags)164433d6423SLionel Sambuc miscflagstr(const u32_t flags)
165433d6423SLionel Sambuc {
166433d6423SLionel Sambuc 	static char str[100];
167433d6423SLionel Sambuc 	str[0] = '\0';
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	FLAG(MF_REPLY_PEND);
170433d6423SLionel Sambuc 	FLAG(MF_DELIVERMSG);
171433d6423SLionel Sambuc 	FLAG(MF_KCALL_RESUME);
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 	return str;
174433d6423SLionel Sambuc }
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc char *
schedulerstr(struct proc * scheduler)177433d6423SLionel Sambuc schedulerstr(struct proc *scheduler)
178433d6423SLionel Sambuc {
179433d6423SLionel Sambuc 	if (scheduler != NULL)
180433d6423SLionel Sambuc 	{
181433d6423SLionel Sambuc 		return scheduler->p_name;
182433d6423SLionel Sambuc 	}
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc 	return "KERNEL";
185433d6423SLionel Sambuc }
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc static void
print_proc_name(struct proc * pp)188433d6423SLionel Sambuc print_proc_name(struct proc *pp)
189433d6423SLionel Sambuc {
190433d6423SLionel Sambuc 	char *name = pp->p_name;
191433d6423SLionel Sambuc 	endpoint_t ep = pp->p_endpoint;
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc 	if(name) {
194433d6423SLionel Sambuc 		printf("%s(%d)", name, ep);
195433d6423SLionel Sambuc 	}
196433d6423SLionel Sambuc 	else {
197433d6423SLionel Sambuc 		printf("%d", ep);
198433d6423SLionel Sambuc 	}
199433d6423SLionel Sambuc }
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc static void
print_endpoint(endpoint_t ep)202433d6423SLionel Sambuc print_endpoint(endpoint_t ep)
203433d6423SLionel Sambuc {
204433d6423SLionel Sambuc 	int proc_nr;
205433d6423SLionel Sambuc 	struct proc *pp = NULL;
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc 	switch(ep) {
208433d6423SLionel Sambuc 	case ANY:
209433d6423SLionel Sambuc 		printf("ANY");
210433d6423SLionel Sambuc 	break;
211433d6423SLionel Sambuc 	case SELF:
212433d6423SLionel Sambuc 		printf("SELF");
213433d6423SLionel Sambuc 	break;
214433d6423SLionel Sambuc 	case NONE:
215433d6423SLionel Sambuc 		printf("NONE");
216433d6423SLionel Sambuc 	break;
217433d6423SLionel Sambuc 	default:
218433d6423SLionel Sambuc 		if(!isokendpt(ep, &proc_nr)) {
219433d6423SLionel Sambuc 			printf("??? %d\n", ep);
220433d6423SLionel Sambuc 		}
221433d6423SLionel Sambuc 		else {
222433d6423SLionel Sambuc 			pp = proc_addr(proc_nr);
223433d6423SLionel Sambuc 			if(isemptyp(pp)) {
224433d6423SLionel Sambuc 				printf("??? empty slot %d\n", proc_nr);
225433d6423SLionel Sambuc 			}
226433d6423SLionel Sambuc 			else {
227433d6423SLionel Sambuc 				print_proc_name(pp);
228433d6423SLionel Sambuc 			}
229433d6423SLionel Sambuc 		}
230433d6423SLionel Sambuc 	break;
231433d6423SLionel Sambuc 	}
232433d6423SLionel Sambuc }
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc static void
print_sigmgr(struct proc * pp)235433d6423SLionel Sambuc print_sigmgr(struct proc *pp)
236433d6423SLionel Sambuc {
237433d6423SLionel Sambuc 	endpoint_t sig_mgr, bak_sig_mgr;
238433d6423SLionel Sambuc 	sig_mgr = priv(pp) ? priv(pp)->s_sig_mgr : NONE;
239433d6423SLionel Sambuc 	bak_sig_mgr = priv(pp) ? priv(pp)->s_bak_sig_mgr : NONE;
240433d6423SLionel Sambuc 	if(sig_mgr == NONE) { printf("no sigmgr"); return; }
241433d6423SLionel Sambuc 	printf("sigmgr ");
242433d6423SLionel Sambuc 	print_endpoint(sig_mgr);
243433d6423SLionel Sambuc 	if(bak_sig_mgr != NONE) {
244433d6423SLionel Sambuc 		printf(" / ");
245433d6423SLionel Sambuc 		print_endpoint(bak_sig_mgr);
246433d6423SLionel Sambuc 	}
247433d6423SLionel Sambuc }
248433d6423SLionel Sambuc 
print_proc(struct proc * pp)249433d6423SLionel Sambuc void print_proc(struct proc *pp)
250433d6423SLionel Sambuc {
251433d6423SLionel Sambuc 	endpoint_t dep;
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc 	printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cpu %2d "
254433d6423SLionel Sambuc 			"pdbr 0x%lx rts %s misc %s sched %s ",
255433d6423SLionel Sambuc 		proc_nr(pp), pp->p_name, pp->p_endpoint,
256433d6423SLionel Sambuc 		pp->p_priority, pp->p_user_time,
257433d6423SLionel Sambuc 		pp->p_sys_time, ex64hi(pp->p_cycles),
258433d6423SLionel Sambuc 		ex64lo(pp->p_cycles), pp->p_cpu,
259433d6423SLionel Sambuc #if defined(__i386__)
260433d6423SLionel Sambuc 		pp->p_seg.p_cr3,
261433d6423SLionel Sambuc #elif defined(__arm__)
262433d6423SLionel Sambuc 		pp->p_seg.p_ttbr,
263433d6423SLionel Sambuc #endif
264433d6423SLionel Sambuc 		rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags),
265433d6423SLionel Sambuc 		schedulerstr(pp->p_scheduler));
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	print_sigmgr(pp);
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 	dep = P_BLOCKEDON(pp);
270433d6423SLionel Sambuc 	if(dep != NONE) {
271433d6423SLionel Sambuc 		printf(" blocked on: ");
272433d6423SLionel Sambuc 		print_endpoint(dep);
273433d6423SLionel Sambuc 	}
274433d6423SLionel Sambuc 	printf("\n");
275433d6423SLionel Sambuc }
276433d6423SLionel Sambuc 
print_proc_depends(struct proc * pp,const int level)277433d6423SLionel Sambuc static void print_proc_depends(struct proc *pp, const int level)
278433d6423SLionel Sambuc {
279433d6423SLionel Sambuc 	struct proc *depproc = NULL;
280433d6423SLionel Sambuc 	endpoint_t dep;
281433d6423SLionel Sambuc #define COL { int i; for(i = 0; i < level; i++) printf("> "); }
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc 	if(level >= NR_PROCS) {
284433d6423SLionel Sambuc 		printf("loop??\n");
285433d6423SLionel Sambuc 		return;
286433d6423SLionel Sambuc 	}
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc 	COL
289433d6423SLionel Sambuc 
290433d6423SLionel Sambuc 	print_proc(pp);
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc 	COL
293433d6423SLionel Sambuc 	proc_stacktrace(pp);
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc 
296433d6423SLionel Sambuc 	dep = P_BLOCKEDON(pp);
297433d6423SLionel Sambuc 	if(dep != NONE && dep != ANY) {
298433d6423SLionel Sambuc 		int procno;
299433d6423SLionel Sambuc 		if(isokendpt(dep, &procno)) {
300433d6423SLionel Sambuc 			depproc = proc_addr(procno);
301433d6423SLionel Sambuc 			if(isemptyp(depproc))
302433d6423SLionel Sambuc 				depproc = NULL;
303433d6423SLionel Sambuc 		}
304433d6423SLionel Sambuc 		if (depproc)
305433d6423SLionel Sambuc 			print_proc_depends(depproc, level+1);
306433d6423SLionel Sambuc 	}
307433d6423SLionel Sambuc }
308433d6423SLionel Sambuc 
print_proc_recursive(struct proc * pp)309433d6423SLionel Sambuc void print_proc_recursive(struct proc *pp)
310433d6423SLionel Sambuc {
311433d6423SLionel Sambuc 	print_proc_depends(pp, 0);
312433d6423SLionel Sambuc }
313433d6423SLionel Sambuc 
314*c8a9900bSCristiano Giuffrida #if DEBUG_DUMPIPC || DEBUG_DUMPIPCF
mtypename(int mtype,int * possible_callname)315433d6423SLionel Sambuc static const char *mtypename(int mtype, int *possible_callname)
316433d6423SLionel Sambuc {
317433d6423SLionel Sambuc 	char *callname = NULL, *errname = NULL;
318433d6423SLionel Sambuc 	/* use generated file to recognize message types
319433d6423SLionel Sambuc 	 *
320433d6423SLionel Sambuc 	 * we try to match both error numbers and call numbers, as the
321433d6423SLionel Sambuc 	 * reader can probably decide from context what's going on.
322433d6423SLionel Sambuc 	 *
323433d6423SLionel Sambuc 	 * whenever it might be a call number we tell the caller so the
324433d6423SLionel Sambuc 	 * call message fields can be decoded if known.
325433d6423SLionel Sambuc 	 */
326433d6423SLionel Sambuc 	switch(mtype) {
327433d6423SLionel Sambuc #define IDENT(x) case x: callname = #x; *possible_callname = 1; break;
328433d6423SLionel Sambuc #include "kernel/extracted-mtype.h"
329433d6423SLionel Sambuc #undef IDENT
330433d6423SLionel Sambuc 	}
331433d6423SLionel Sambuc 	switch(mtype) {
332433d6423SLionel Sambuc #define IDENT(x) case x: errname = #x; break;
333433d6423SLionel Sambuc #include "kernel/extracted-errno.h"
334433d6423SLionel Sambuc #undef IDENT
335433d6423SLionel Sambuc 	}
336433d6423SLionel Sambuc 
337433d6423SLionel Sambuc 	/* no match */
338433d6423SLionel Sambuc 	if(!errname && !callname)
339433d6423SLionel Sambuc 		return NULL;
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc 	/* 2 matches */
342433d6423SLionel Sambuc 	if(errname && callname) {
343433d6423SLionel Sambuc 		static char typename[100];
344433d6423SLionel Sambuc 		strcpy(typename, errname);
345433d6423SLionel Sambuc 		strcat(typename, " / ");
346433d6423SLionel Sambuc 		strcat(typename, callname);
347433d6423SLionel Sambuc 		return typename;
348433d6423SLionel Sambuc 	}
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc 	if(errname) return errname;
351433d6423SLionel Sambuc 
352433d6423SLionel Sambuc 	assert(callname);
353433d6423SLionel Sambuc 	return callname;
354433d6423SLionel Sambuc }
355433d6423SLionel Sambuc 
printproc(struct proc * rp)356433d6423SLionel Sambuc static void printproc(struct proc *rp)
357433d6423SLionel Sambuc {
358433d6423SLionel Sambuc 	if (rp)
359433d6423SLionel Sambuc 		printf(" %s(%d)", rp->p_name, rp - proc);
360433d6423SLionel Sambuc 	else
361433d6423SLionel Sambuc 		printf(" kernel");
362433d6423SLionel Sambuc }
363433d6423SLionel Sambuc 
printparam(const char * name,const void * data,size_t size)364433d6423SLionel Sambuc static void printparam(const char *name, const void *data, size_t size)
365433d6423SLionel Sambuc {
366433d6423SLionel Sambuc 	printf(" %s=", name);
367433d6423SLionel Sambuc 	switch (size) {
368433d6423SLionel Sambuc 		case sizeof(char):	printf("%d", *(char *) data);	break;
369433d6423SLionel Sambuc 		case sizeof(short):	printf("%d", *(short *) data);	break;
370433d6423SLionel Sambuc 		case sizeof(int):	printf("%d", *(int *) data);	break;
371433d6423SLionel Sambuc 		default:		printf("(%u bytes)", size);	break;
372433d6423SLionel Sambuc 	}
373433d6423SLionel Sambuc }
374433d6423SLionel Sambuc 
375433d6423SLionel Sambuc #ifdef DEBUG_DUMPIPC_NAMES
namematch(char ** names,int nnames,char * name)376433d6423SLionel Sambuc static int namematch(char **names, int nnames, char *name)
377433d6423SLionel Sambuc {
378433d6423SLionel Sambuc 	int i;
379433d6423SLionel Sambuc 	for(i = 0; i < nnames; i++)
380433d6423SLionel Sambuc 		if(!strcmp(names[i], name))
381433d6423SLionel Sambuc 			return 1;
382433d6423SLionel Sambuc 	return 0;
383433d6423SLionel Sambuc }
384433d6423SLionel Sambuc #endif
385433d6423SLionel Sambuc 
printmsg(message * msg,struct proc * src,struct proc * dst,char operation,int printparams)386*c8a9900bSCristiano Giuffrida void printmsg(message *msg, struct proc *src, struct proc *dst,
387433d6423SLionel Sambuc 	char operation, int printparams)
388433d6423SLionel Sambuc {
389433d6423SLionel Sambuc 	const char *name;
390433d6423SLionel Sambuc 	int mtype = msg->m_type, mightbecall = 0;
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc #ifdef DEBUG_DUMPIPC_NAMES
393433d6423SLionel Sambuc   {
394433d6423SLionel Sambuc 	char *names[] = DEBUG_DUMPIPC_NAMES;
395433d6423SLionel Sambuc 	int nnames = sizeof(names)/sizeof(names[0]);
396433d6423SLionel Sambuc 
397433d6423SLionel Sambuc 	/* skip printing messages for messages neither to
398433d6423SLionel Sambuc 	 * or from DEBUG_DUMPIPC_EP if it is defined; either
399433d6423SLionel Sambuc 	 * can be NULL to indicate kernel
400433d6423SLionel Sambuc 	 */
401433d6423SLionel Sambuc 	if(!(src && namematch(names, nnames, src->p_name)) &&
402433d6423SLionel Sambuc 	   !(dst && namematch(names, nnames, dst->p_name))) {
403433d6423SLionel Sambuc 		return;
404433d6423SLionel Sambuc 	}
405433d6423SLionel Sambuc   }
406433d6423SLionel Sambuc #endif
407433d6423SLionel Sambuc 
408433d6423SLionel Sambuc 	/* source, destination and message type */
409433d6423SLionel Sambuc 	printf("%c", operation);
410433d6423SLionel Sambuc 	printproc(src);
411433d6423SLionel Sambuc 	printproc(dst);
412433d6423SLionel Sambuc 	name = mtypename(mtype, &mightbecall);
413433d6423SLionel Sambuc 	if (name) {
414433d6423SLionel Sambuc 		printf(" %s(%d/0x%x)", name, mtype, mtype);
415433d6423SLionel Sambuc 	} else {
416433d6423SLionel Sambuc 		printf(" %d/0x%x", mtype, mtype);
417433d6423SLionel Sambuc 	}
418433d6423SLionel Sambuc 
419433d6423SLionel Sambuc 	if (mightbecall && printparams) {
420433d6423SLionel Sambuc #define IDENT(x, y) if (mtype == x) printparam(#y, &msg->y, sizeof(msg->y));
421433d6423SLionel Sambuc #include "kernel/extracted-mfield.h"
422433d6423SLionel Sambuc #undef IDENT
423433d6423SLionel Sambuc 	}
424433d6423SLionel Sambuc 	printf("\n");
425433d6423SLionel Sambuc }
426433d6423SLionel Sambuc #endif
427433d6423SLionel Sambuc 
428433d6423SLionel Sambuc #if DEBUG_IPCSTATS
429433d6423SLionel Sambuc #define IPCPROCS (NR_PROCS+1)	/* number of slots we need */
430433d6423SLionel Sambuc #define KERNELIPC NR_PROCS	/* slot number to use for kernel calls */
431433d6423SLionel Sambuc static int messages[IPCPROCS][IPCPROCS];
432433d6423SLionel Sambuc 
433433d6423SLionel Sambuc #define PRINTSLOTS 20
434433d6423SLionel Sambuc static struct {
435433d6423SLionel Sambuc 	int src, dst, messages;
436433d6423SLionel Sambuc } winners[PRINTSLOTS];
437433d6423SLionel Sambuc static int total, goodslots;
438433d6423SLionel Sambuc 
printstats(int ticks)439433d6423SLionel Sambuc static void printstats(int ticks)
440433d6423SLionel Sambuc {
441433d6423SLionel Sambuc 	int i;
442433d6423SLionel Sambuc 	for(i = 0; i < goodslots; i++) {
443433d6423SLionel Sambuc #define name(s) (s == KERNELIPC ? "kernel" : proc_addr(s)->p_name)
444433d6423SLionel Sambuc #define persec(n) (system_hz*(n)/ticks)
445433d6423SLionel Sambuc 		char	*n1 = name(winners[i].src),
446433d6423SLionel Sambuc 			*n2 = name(winners[i].dst);
447433d6423SLionel Sambuc 		printf("%2d.  %8s -> %8s  %9d/s\n",
448433d6423SLionel Sambuc 			i, n1, n2, persec(winners[i].messages));
449433d6423SLionel Sambuc 	}
450433d6423SLionel Sambuc 	printf("total %d/s\n", persec(total));
451433d6423SLionel Sambuc }
452433d6423SLionel Sambuc 
sortstats(void)453433d6423SLionel Sambuc static void sortstats(void)
454433d6423SLionel Sambuc {
455433d6423SLionel Sambuc 	/* Print top message senders/receivers. */
456433d6423SLionel Sambuc 	int src_slot, dst_slot;
457433d6423SLionel Sambuc 	total = goodslots = 0;
458433d6423SLionel Sambuc 	for(src_slot = 0; src_slot < IPCPROCS; src_slot++) {
459433d6423SLionel Sambuc 		for(dst_slot = 0; dst_slot < IPCPROCS; dst_slot++) {
460433d6423SLionel Sambuc 			int w = PRINTSLOTS, rem,
461433d6423SLionel Sambuc 				n = messages[src_slot][dst_slot];
462433d6423SLionel Sambuc 			total += n;
463433d6423SLionel Sambuc 			while(w > 0 && n > winners[w-1].messages)
464433d6423SLionel Sambuc 				w--;
465433d6423SLionel Sambuc 			if(w >= PRINTSLOTS) continue;
466433d6423SLionel Sambuc 
467433d6423SLionel Sambuc 			/* This combination has beaten the current winners
468433d6423SLionel Sambuc 			 * and should be inserted at position 'w.'
469433d6423SLionel Sambuc 			 */
470433d6423SLionel Sambuc 			rem = PRINTSLOTS-w-1;
471433d6423SLionel Sambuc 			assert(rem >= 0);
472433d6423SLionel Sambuc 			assert(rem < PRINTSLOTS);
473433d6423SLionel Sambuc 			if(rem > 0) {
474433d6423SLionel Sambuc 				assert(w+1 <= PRINTSLOTS-1);
475433d6423SLionel Sambuc 				assert(w >= 0);
476433d6423SLionel Sambuc 				memmove(&winners[w+1], &winners[w],
477433d6423SLionel Sambuc 					rem*sizeof(winners[0]));
478433d6423SLionel Sambuc 			}
479433d6423SLionel Sambuc 			winners[w].src = src_slot;
480433d6423SLionel Sambuc 			winners[w].dst = dst_slot;
481433d6423SLionel Sambuc 			winners[w].messages = n;
482433d6423SLionel Sambuc 			if(goodslots < PRINTSLOTS) goodslots++;
483433d6423SLionel Sambuc 		}
484433d6423SLionel Sambuc 	}
485433d6423SLionel Sambuc }
486433d6423SLionel Sambuc 
487433d6423SLionel Sambuc #define proc2slot(p, s) { \
488433d6423SLionel Sambuc 	if(p) { s = p->p_nr; } \
489433d6423SLionel Sambuc 	else { s = KERNELIPC; } \
490433d6423SLionel Sambuc 	assert(s >= 0 && s < IPCPROCS); \
491433d6423SLionel Sambuc }
492433d6423SLionel Sambuc 
statmsg(message * msg,struct proc * srcp,struct proc * dstp)493433d6423SLionel Sambuc static void statmsg(message *msg, struct proc *srcp, struct proc *dstp)
494433d6423SLionel Sambuc {
495433d6423SLionel Sambuc 	int src, dst, now, secs, dt;
496433d6423SLionel Sambuc 	static int lastprint;
497433d6423SLionel Sambuc 
498433d6423SLionel Sambuc 	/* Stat message. */
499433d6423SLionel Sambuc 	assert(src);
500433d6423SLionel Sambuc 	proc2slot(srcp, src);
501433d6423SLionel Sambuc 	proc2slot(dstp, dst);
502433d6423SLionel Sambuc 	messages[src][dst]++;
503433d6423SLionel Sambuc 
504433d6423SLionel Sambuc 	/* Print something? */
505433d6423SLionel Sambuc 	now = get_monotonic();
506433d6423SLionel Sambuc 	dt = now - lastprint;
507433d6423SLionel Sambuc 	secs = dt/system_hz;
508433d6423SLionel Sambuc 	if(secs >= 30) {
509433d6423SLionel Sambuc 		memset(winners, 0, sizeof(winners));
510433d6423SLionel Sambuc 		sortstats();
511433d6423SLionel Sambuc 		printstats(dt);
512433d6423SLionel Sambuc 		memset(messages, 0, sizeof(messages));
513433d6423SLionel Sambuc 		lastprint = now;
514433d6423SLionel Sambuc 	}
515433d6423SLionel Sambuc }
516433d6423SLionel Sambuc #endif
517433d6423SLionel Sambuc 
518433d6423SLionel Sambuc #if DEBUG_IPC_HOOK
hook_ipc_msgkcall(message * msg,struct proc * proc)519433d6423SLionel Sambuc void hook_ipc_msgkcall(message *msg, struct proc *proc)
520433d6423SLionel Sambuc {
521433d6423SLionel Sambuc #if DEBUG_DUMPIPC
522433d6423SLionel Sambuc 	printmsg(msg, proc, NULL, 'k', 1);
523433d6423SLionel Sambuc #endif
524433d6423SLionel Sambuc }
525433d6423SLionel Sambuc 
hook_ipc_msgkresult(message * msg,struct proc * proc)526433d6423SLionel Sambuc void hook_ipc_msgkresult(message *msg, struct proc *proc)
527433d6423SLionel Sambuc {
528433d6423SLionel Sambuc #if DEBUG_DUMPIPC
529433d6423SLionel Sambuc 	printmsg(msg, NULL, proc, 'k', 0);
530433d6423SLionel Sambuc #endif
531433d6423SLionel Sambuc #if DEBUG_IPCSTATS
532433d6423SLionel Sambuc 	statmsg(msg, proc, NULL);
533433d6423SLionel Sambuc #endif
534433d6423SLionel Sambuc }
535433d6423SLionel Sambuc 
hook_ipc_msgrecv(message * msg,struct proc * src,struct proc * dst)536433d6423SLionel Sambuc void hook_ipc_msgrecv(message *msg, struct proc *src, struct proc *dst)
537433d6423SLionel Sambuc {
538433d6423SLionel Sambuc #if DEBUG_DUMPIPC
539433d6423SLionel Sambuc 	printmsg(msg, src, dst, 'r', 0);
540433d6423SLionel Sambuc #endif
541433d6423SLionel Sambuc #if DEBUG_IPCSTATS
542433d6423SLionel Sambuc 	statmsg(msg, src, dst);
543433d6423SLionel Sambuc #endif
544433d6423SLionel Sambuc }
545433d6423SLionel Sambuc 
hook_ipc_msgsend(message * msg,struct proc * src,struct proc * dst)546433d6423SLionel Sambuc void hook_ipc_msgsend(message *msg, struct proc *src, struct proc *dst)
547433d6423SLionel Sambuc {
548433d6423SLionel Sambuc #if DEBUG_DUMPIPC
549433d6423SLionel Sambuc 	printmsg(msg, src, dst, 's', 1);
550433d6423SLionel Sambuc #endif
551433d6423SLionel Sambuc }
552433d6423SLionel Sambuc 
hook_ipc_clear(struct proc * p)553433d6423SLionel Sambuc void hook_ipc_clear(struct proc *p)
554433d6423SLionel Sambuc {
555433d6423SLionel Sambuc #if DEBUG_IPCSTATS
556433d6423SLionel Sambuc 	int slot, i;
557433d6423SLionel Sambuc 	assert(p);
558433d6423SLionel Sambuc 	proc2slot(p, slot);
559433d6423SLionel Sambuc 	for(i = 0; i < IPCPROCS; i++)
560433d6423SLionel Sambuc 		messages[slot][i] = messages[i][slot] = 0;
561433d6423SLionel Sambuc #endif
562433d6423SLionel Sambuc }
563433d6423SLionel Sambuc #endif
564