Syscall tracing
[akaros.git] / kern / src / monitor.c
1 // Simple command-line kernel monitor useful for
2 // controlling the kernel and exploring the system interactively.
3
4 #ifdef __SHARC__
5 #pragma nosharc
6 #endif
7
8 #include <arch/arch.h>
9 #include <stab.h>
10 #include <smp.h>
11 #include <arch/console.h>
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <monitor.h>
17 #include <trap.h>
18 #include <pmap.h>
19 #include <kdebug.h>
20 #include <testing.h>
21 #include <kfs.h>
22 #include <manager.h>
23 #include <schedule.h>
24 #include <resource.h>
25 #include <kdebug.h>
26 #include <syscall.h>
27 #include <kmalloc.h>
28
29 #include <ros/memlayout.h>
30
31 #define CMDBUF_SIZE     80      // enough for one VGA text line
32
33 typedef struct command {
34         const char *NTS name;
35         const char *NTS desc;
36         // return -1 to force monitor to exit
37         int (*func)(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf);
38 } command_t;
39
40 static command_t (RO commands)[] = {
41         { "help", "Display this list of commands", mon_help },
42         { "kerninfo", "Display information about the kernel", mon_kerninfo },
43         { "backtrace", "Dump a backtrace", mon_backtrace },
44         { "reboot", "Take a ride to the South Bay", mon_reboot },
45         { "showmapping", "Shows VA->PA mappings", mon_showmapping},
46         { "setmapperm", "Sets permissions on a VA->PA mapping", mon_setmapperm},
47         { "cpuinfo", "Prints CPU diagnostics", mon_cpuinfo},
48         { "ps", "Prints process list", mon_ps},
49         { "nanwan", "Meet Nanwan!!", mon_nanwan},
50         { "kfs_ls", "List files in KFS", mon_kfs_ls},
51         { "kfs_run", "Create and run a program from KFS", mon_kfs_run},
52         { "kfs_cat", "Dumps text from a file from KFS", mon_kfs_cat},
53         { "manager", "Run the manager", mon_manager},
54         { "procinfo", "Show information about processes", mon_procinfo},
55         { "exit", "Leave the monitor", mon_exit},
56         { "kfunc", "Run a kernel function directly (!!!)", mon_kfunc},
57         { "notify", "Notify a process.  Vcoreid will skip their prefs", mon_notify},
58         { "measure", "Run a specific measurement", mon_measure},
59         { "trace", "Run a specific measurement", mon_trace},
60 };
61 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
62
63 /***** Implementations of basic kernel monitor commands *****/
64
65 int mon_help(int argc, char **argv, trapframe_t *tf)
66 {
67         int i;
68
69         for (i = 0; i < NCOMMANDS; i++)
70                 cprintf("%s - %s\n", commands[i].name, commands[i].desc);
71         return 0;
72 }
73
74 int mon_ps(int argc, char** argv, trapframe_t *tf)
75 {
76         print_allpids();
77         return 0;
78 }
79
80 int mon_kerninfo(int argc, char **argv, trapframe_t *tf)
81 {
82         extern char (RO SNT _start)[], (RO SNT etext)[], (RO SNT edata)[], (RO SNT end)[];
83
84         cprintf("Special kernel symbols:\n");
85         cprintf("  _start %08x (virt)  %08x (phys)\n", _start, (uint32_t)(_start - KERNBASE));
86         cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, (uint32_t)(etext - KERNBASE));
87         cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, (uint32_t)(edata - KERNBASE));
88         cprintf("  end    %08x (virt)  %08x (phys)\n", end, (uint32_t)(end - KERNBASE));
89         cprintf("Kernel executable memory footprint: %dKB\n",
90                 (uint32_t)(end-_start+1023)/1024);
91         return 0;
92 }
93
94 #if 0
95 zra: not called
96 static char RO* function_of(uint32_t address)
97 {
98         extern stab_t (RO stab)[], (RO estab)[];
99         extern char (RO stabstr)[];
100         stab_t* symtab;
101         stab_t* best_symtab = 0;
102         uint32_t best_func = 0;
103
104         // ugly and unsorted
105         for (symtab = stab; symtab < estab; symtab++) {
106                 // only consider functions, type = N_FUN
107                 if ((symtab->n_type == N_FUN) &&
108                     (symtab->n_value <= address) &&
109                         (symtab->n_value > best_func)) {
110                         best_func = symtab->n_value;
111                         best_symtab = symtab;
112                 }
113         }
114         // maybe the first stab really is the right one...  we'll see.
115         if (best_symtab == 0)
116                 return "Function not found!";
117         return stabstr + best_symtab->n_strx;
118 }
119 #endif
120
121 int mon_backtrace(int argc, char **argv, trapframe_t *tf)
122 {
123         backtrace();
124         return 0;
125 }
126
127 int mon_reboot(int argc, char **argv, trapframe_t *tf)
128 {
129         cprintf("[Scottish Accent]: She's goin' down, Cap'n!\n");
130         reboot();
131
132         // really, should never see this
133         cprintf("Sigh....\n");
134         return 0;
135 }
136
137 int mon_showmapping(int argc, char **argv, trapframe_t *tf)
138 {
139         if (argc < 2) {
140                 cprintf("Shows virtual -> physical mappings for a virtual address range.\n");
141                 cprintf("Usage: showmapping START_ADDR [END_ADDR]\n");
142                 return 1;
143         }
144         pde_t* pgdir = (pde_t*)vpd;
145         pte_t *pte, *pde;
146         page_t* page;
147         uintptr_t start, i;
148         size_t size;
149         start = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
150         size = (argc == 2) ? 1 : strtol(argv[2], 0, 16) - start;
151         if (size/PGSIZE > 512) {
152                 cprintf("Not going to do this for more than 512 items\n");
153                 return 1;
154         }
155
156         show_mapping(start,size);
157         return 0;
158 }
159
160 int mon_setmapperm(int argc, char **argv, trapframe_t *tf)
161 {
162 #ifndef __i386__
163         cprintf("I don't support this call yet!\n");
164         return 1;
165 #else
166         if (argc < 3) {
167                 cprintf("Sets VIRT_ADDR's mapping's permissions to PERMS (in hex)\n");
168                 cprintf("Only affects the lowest level PTE.  To adjust the PDE, do the math.\n");
169                 cprintf("Be careful with this around UVPT, VPT, and friends.\n");
170                 cprintf("Usage: setmapperm VIRT_ADDR PERMS\n");
171                 return 1;
172         }
173         pde_t*COUNT(PTSIZE) pgdir = (pde_t*COUNT(PTSIZE))vpd;
174         pte_t *pte, *pde;
175         page_t* page;
176         uintptr_t va;
177         va = ROUNDDOWN(strtol(argv[1], 0, 16), PGSIZE);
178         page = page_lookup(pgdir, (void*SNT)va, &pte);
179         if (!page) {
180                 cprintf("No such mapping\n");
181                 return 1;
182         }
183         pde = &pgdir[PDX(va)];
184         cprintf("   Virtual    Physical  Ps Dr Ac CD WT U W\n");
185         cprintf("------------------------------------------\n");
186         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page),
187                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5,
188                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2,
189                (*pte & *pde & PTE_W) >> 1);
190         *pte = PTE_ADDR(*pte) | (*pte & PTE_PS) |
191                (PGOFF(strtol(argv[2], 0, 16)) & ~PTE_PS ) | PTE_P;
192         cprintf("%08p  %08p  %1d  %1d  %1d  %1d  %1d  %1d %1d\n", va, page2pa(page),
193                (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6, (*pte & PTE_A) >> 5,
194                (*pte & PTE_PCD) >> 4, (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2,
195                (*pte & *pde & PTE_W) >> 1);
196         return 0;
197 #endif
198 }
199
200 int mon_cpuinfo(int argc, char **argv, trapframe_t *tf)
201 {
202         cprintf("Number of CPUs detected: %d\n", num_cpus);
203         cprintf("Calling CPU's ID: 0x%08x\n", core_id());
204
205         if (argc < 2)
206                 smp_call_function_self(test_print_info_handler, NULL, 0);
207         else
208                 smp_call_function_single(strtol(argv[1], 0, 10),
209                                          test_print_info_handler, NULL, 0);
210         return 0;
211 }
212
213 int mon_manager(int argc, char** argv, trapframe_t *tf)
214 {
215         manager();
216         panic("should never get here");
217         return 0;
218 }
219
220 int mon_nanwan(int argc, char **argv, trapframe_t *tf)
221 {
222         /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
223          * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines tall.
224          */
225         printk("\n");
226         printk("             .-.  .-.\n");
227         printk("             |  \\/  |\n");
228         printk("            /,   ,_  `'-.\n");
229         printk("          .-|\\   /`\\     '. \n");
230         printk("        .'  0/   | 0\\  \\_  `\".  \n");
231         printk("     .-'  _,/    '--'.'|#''---'\n");
232         printk("      `--'  |       /   \\#\n");
233         printk("            |      /     \\#\n");
234         printk("            \\     ;|\\    .\\#\n");
235         printk("            |' ' //  \\   ::\\# \n");
236         printk("            \\   /`    \\   ':\\#\n");
237         printk("             `\"`       \\..   \\#\n");
238         printk("                        \\::.  \\#\n");
239         printk("                         \\::   \\#\n");
240         printk("                          \\'  .:\\#\n");
241         printk("                           \\  :::\\#\n");
242         printk("                            \\  '::\\#\n");
243         printk("                             \\     \\#\n");
244         printk("                              \\:.   \\#\n");
245         printk("                               \\::   \\#\n");
246         printk("                                \\'   .\\#\n");
247         printk("                             jgs \\   ::\\#\n");
248         printk("                                  \\      \n");
249         return 0;
250 }
251
252 int mon_kfs_ls(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
253 {
254         printk("Files in KFS:\n-------------------------------\n");
255         for (int i = 0; i < MAX_KFS_FILES; i++)
256                 if (kfs[i].name[0])
257                         printk("%s\n", kfs[i].name);
258         return 0;
259 }
260
261 int mon_kfs_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
262 {
263         if (argc != 2) {
264                 printk("Usage: kfs_run FILENAME\n");
265                 return 1;
266         }
267         int kfs_inode = kfs_lookup_path(argv[1]);
268         if (kfs_inode < 0) {
269                 printk("Bad filename!\n");
270                 return 1;
271         }
272         struct proc *p = kfs_proc_create(kfs_inode);
273         // go from PROC_CREATED->PROC_RUNNABLE_S
274         spin_lock(&p->proc_lock); // might not be necessary for a mon function
275         __proc_set_state(p, PROC_RUNNABLE_S);
276         schedule_proc(p);
277         spin_unlock(&p->proc_lock);
278         proc_decref(p, 1); // let go of the reference created in proc_create()
279         // Should never return from schedule (env_pop in there)
280         // also note you may not get the process you created, in the event there
281         // are others floating around that are runnable
282         schedule();
283         return 0;
284 }
285
286 int mon_kfs_cat(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
287 {
288         if (argc != 2) {
289                 printk("Usage: kfs_cat FILENAME\n");
290                 return 1;
291         }
292         int kfs_inode = kfs_lookup_path(argv[1]);
293         if (kfs_inode < 0) {
294                 printk("Bad filename!\n");
295                 return 1;
296         }
297         kfs_cat(kfs_inode);
298         return 0;
299 }
300
301 int mon_procinfo(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
302 {
303         if (argc < 2) {
304                 printk("Usage: procinfo OPTION\n");
305                 printk("\tidlecores: show idle core map\n");
306                 printk("\tall: show all active pids\n");
307                 printk("\trunnable: show proc_runnablelist\n");
308                 printk("\tresources: show resources wanted/granted for all procs\n");
309                 printk("\tpid NUM: show a lot of info for proc NUM\n");
310                 printk("\tunlock NUM: unlock the lock for proc NUM (OMG!!!)\n");
311                 printk("\tkill NUM: destroy proc NUM\n");
312                 return 1;
313         }
314         if (!strcmp(argv[1], "idlecores")) {
315                 print_idlecoremap();
316         } else if (!strcmp(argv[1], "all")) {
317                 print_allpids();
318         } else if (!strcmp(argv[1], "runnable")) {
319                 dump_proclist(&proc_runnablelist);
320         } else if (!strcmp(argv[1], "resources")) {
321                 print_all_resources();
322         } else if (!strcmp(argv[1], "pid")) {
323                 if (argc != 3) {
324                         printk("Give me a pid number.\n");
325                         return 1;
326                 }
327                 print_proc_info(strtol(argv[2], 0, 0));
328         } else if (!strcmp(argv[1], "unlock")) {
329                 if (argc != 3) {
330                         printk("Give me a pid number.\n");
331                         return 1;
332                 }
333                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
334                 if (!p) {
335                         printk("No such proc\n");
336                         return 1;
337                 }
338                 spin_unlock(&p->proc_lock);
339                 proc_decref(p, 1);
340         } else if (!strcmp(argv[1], "kill")) {
341                 if (argc != 3) {
342                         printk("Give me a pid number.\n");
343                         return 1;
344                 }
345                 struct proc *p = pid2proc(strtol(argv[2], 0, 0));
346                 if (!p) {
347                         printk("No such proc\n");
348                         return 1;
349                 }
350                 proc_destroy(p);
351                 proc_decref(p, 1);
352         } else {
353                 printk("Bad option\n");
354                 return 1;
355         }
356         return 0;
357 }
358
359 int mon_exit(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
360 {
361         return -1;
362 }
363
364 int mon_kfunc(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
365 {
366         #ifndef __i386__
367         printk("Only supported on x86 for now.  =(\n");
368         return -1;
369         #endif
370
371         void (*func)(void *arg, ...);
372
373         if (argc < 2) {
374                 printk("Usage: kfunc FUNCTION [arg1] [arg2] [etc]\n");
375                 printk("Arguments must be in hex.  Can take 6 args.\n");
376                 return 1;
377         }
378         func = debug_get_fn_addr(argv[1]);
379         if (!func) {
380                 printk("Function not found.\n");
381                 return 1;
382         }
383         /* Not elegant, but whatever.  maybe there's a better syntax, or we can do
384          * it with asm magic. */
385         switch (argc) {
386                 case 2: /* have to fake one arg */
387                         func((void*)0);
388                         break;
389                 case 3: /* the real first arg */
390                         func((void*)strtol(argv[2], 0, 16));
391                         break;
392                 case 4:
393                         func((void*)strtol(argv[2], 0, 16),
394                                     strtol(argv[3], 0, 16));
395                         break;
396                 case 5:
397                         func((void*)strtol(argv[2], 0, 16),
398                                     strtol(argv[3], 0, 16),
399                                     strtol(argv[4], 0, 16));
400                         break;
401                 case 6:
402                         func((void*)strtol(argv[2], 0, 16),
403                                     strtol(argv[3], 0, 16),
404                                     strtol(argv[4], 0, 16),
405                                     strtol(argv[5], 0, 16));
406                         break;
407                 case 7:
408                         func((void*)strtol(argv[2], 0, 16),
409                                     strtol(argv[3], 0, 16),
410                                     strtol(argv[4], 0, 16),
411                                     strtol(argv[5], 0, 16),
412                                     strtol(argv[6], 0, 16));
413                         break;
414                 case 8:
415                         func((void*)strtol(argv[2], 0, 16),
416                                     strtol(argv[3], 0, 16),
417                                     strtol(argv[4], 0, 16),
418                                     strtol(argv[5], 0, 16),
419                                     strtol(argv[6], 0, 16),
420                                     strtol(argv[7], 0, 16));
421                         break;
422                 default:
423                         printk("Bad number of arguments.\n");
424                         return -1;
425         }
426         return 0;
427 }
428
429 int mon_notify(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
430 {
431         struct proc *p;
432         unsigned int num;
433         uint32_t vcoreid;
434
435         if (argc < 3) {
436                 printk("Usage: notify PID NUM [VCOREID]\n");
437                 return 1;
438         }
439         p = pid2proc(strtol(argv[1], 0, 0));
440         if (!p) {
441                 printk("No such proc\n");
442                 return 1;
443         }
444         num = strtol(argv[2], 0, 0);
445         if (argc == 4) {
446                 vcoreid = strtol(argv[3], 0, 0);
447                 do_notify(p, vcoreid, num, 0);
448         } else {
449                 proc_notify(p, num, 0);
450         }
451         proc_decref(p, 1);
452         return 0;
453 }
454
455 /* Micro-benchmarky Measurements */
456 int mon_measure(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
457 {
458         if (argc < 2) {
459                 printk("Usage: measure OPTION\n");
460                 printk("\topt1: whatever\n");
461                 return 1;
462         }
463         if (!strcmp(argv[1], "opt1")) {
464                 print_idlecoremap();
465         } else if (!strcmp(argv[1], "opt2")) {
466                 if (argc != 3) {
467                         printk("ERRRRRRRRRR.\n");
468                         return 1;
469                 }
470                 print_proc_info(strtol(argv[2], 0, 0));
471         } else {
472                 printk("Bad option\n");
473                 return 1;
474         }
475         return 0;
476 }
477
478 int mon_trace(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
479 {
480         if (argc < 2) {
481                 printk("Usage: trace OPTION\n");
482                 printk("\tsyscall start [silent] [pid]: starts tracing\n");
483                 printk("\tsyscall stop: stops tracing, prints if it was silent\n");
484                 return 1;
485         }
486         if (!strcmp(argv[1], "syscall")) {
487                 if (argc < 3) {
488                         printk("Need a start or stop.\n");
489                         return 1;
490                 }
491                 if (!strcmp(argv[2], "start")) {
492                         bool all = TRUE;
493                         bool silent = FALSE;
494                         struct proc *p = NULL;
495                         if (argc >= 4) {
496                                 silent = (bool)strtol(argv[3], 0, 0);
497                         }
498                         if (argc >= 5) {
499                                 all = FALSE;
500                                 p = pid2proc(strtol(argv[4], 0, 0));
501                                 if (!p) {
502                                         printk("No such process\n");
503                                         return 1;
504                                 }
505                         }
506                         systrace_start(silent);
507                         if (systrace_reg(all, p))
508                                 printk("No room to trace more processes\n");
509                 } else if (!strcmp(argv[2], "stop")) {
510                         /* Stop and print for all processes */
511                         systrace_stop();
512                         systrace_print(TRUE, 0);
513                         systrace_clear_buffer();
514                 }
515         } else if (!strcmp(argv[1], "opt2")) {
516                 if (argc != 3) {
517                         printk("ERRRRRRRRRR.\n");
518                         return 1;
519                 }
520                 print_proc_info(strtol(argv[2], 0, 0));
521         } else {
522                 printk("Bad option\n");
523                 return 1;
524         }
525         return 0;
526 }
527
528 /***** Kernel monitor command interpreter *****/
529
530 #define WHITESPACE "\t\r\n "
531 #define MAXARGS 16
532
533 static int runcmd(char *NTS real_buf, trapframe_t *tf) {
534         char * buf = NTEXPAND(real_buf);
535         int argc;
536         char *NTS argv[MAXARGS];
537         int i;
538
539         // Parse the command buffer into whitespace-separated arguments
540         argc = 0;
541         argv[argc] = 0;
542         while (1) {
543                 // gobble whitespace
544                 while (*buf && strchr(WHITESPACE, *buf))
545                         *buf++ = 0;
546                 if (*buf == 0)
547                         break;
548
549                 // save and scan past next arg
550                 if (argc == MAXARGS-1) {
551                         cprintf("Too many arguments (max %d)\n", MAXARGS);
552                         return 0;
553                 }
554                 //This will get fucked at runtime..... in the ASS
555                 argv[argc++] = buf;
556                 while (*buf && !strchr(WHITESPACE, *buf))
557                         buf++;
558         }
559         argv[argc] = 0;
560
561         // Lookup and invoke the command
562         if (argc == 0)
563                 return 0;
564         for (i = 0; i < NCOMMANDS; i++) {
565                 if (strcmp(argv[0], commands[i].name) == 0)
566                         return commands[i].func(argc, argv, tf);
567         }
568         cprintf("Unknown command '%s'\n", argv[0]);
569         return 0;
570 }
571
572 void monitor(trapframe_t *tf) {
573         static spinlock_t monitor_lock = SPINLOCK_INITIALIZER;
574         spin_lock_irqsave(&monitor_lock);
575
576         char *buf;
577
578         printk("Welcome to the ROS kernel monitor on core %d!\n", core_id());
579         printk("Type 'help' for a list of commands.\n");
580
581         if (tf != NULL)
582                 print_trapframe(tf);
583
584         spin_unlock_irqsave(&monitor_lock);
585         while (1) {
586                 spin_lock_irqsave(&monitor_lock);
587                 buf = readline("K> ");
588                 if (buf != NULL) {
589                         spin_unlock_irqsave(&monitor_lock);
590                         if (runcmd(buf, tf) < 0)
591                                 break;
592                 }
593         }
594 }