21ecc4aac26ff3dbc9da147317efed32e91909ae
[akaros.git] / kern / monitor.c
1 // Simple command-line kernel monitor useful for
2 // controlling the kernel and exploring the system interactively.
3
4 #include <inc/stdio.h>
5 #include <inc/string.h>
6 #include <inc/memlayout.h>
7 #include <inc/assert.h>
8 #include <inc/x86.h>
9 #include <inc/elf.h>
10
11 #include <kern/console.h>
12 #include <kern/monitor.h>
13
14 #define CMDBUF_SIZE     80      // enough for one VGA text line
15
16
17 struct Command {
18         const char *name;
19         const char *desc;
20         // return -1 to force monitor to exit
21         int (*func)(int argc, char** argv, struct Trapframe* tf);
22 };
23
24 static struct Command commands[] = {
25         { "help", "Display this list of commands", mon_help },
26         { "kerninfo", "Display information about the kernel", mon_kerninfo },
27         { "backtrace", "Dump a backtrace", mon_backtrace },
28         { "reboot", "Take a ride to the South Bay", mon_reboot },
29 };
30 #define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
31
32 unsigned read_eip();
33
34 /***** Implementations of basic kernel monitor commands *****/
35
36 int
37 mon_help(int argc, char **argv, struct Trapframe *tf)
38 {
39         int i;
40
41         for (i = 0; i < NCOMMANDS; i++)
42                 cprintf("%s - %s\n", commands[i].name, commands[i].desc);
43         return 0;
44 }
45
46 int
47 mon_kerninfo(int argc, char **argv, struct Trapframe *tf)
48 {
49         extern char _start[], etext[], edata[], end[];
50
51         cprintf("Special kernel symbols:\n");
52         cprintf("  _start %08x (virt)  %08x (phys)\n", _start, _start - KERNBASE);
53         cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, etext - KERNBASE);
54         cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, edata - KERNBASE);
55         cprintf("  end    %08x (virt)  %08x (phys)\n", end, end - KERNBASE);
56         cprintf("Kernel executable memory footprint: %dKB\n",
57                 (end-_start+1023)/1024);
58         return 0;
59 }
60
61 char* function_of(uint32_t address) 
62 {
63         extern stab_t stab[], estab[];
64         extern char stabstr[];
65         stab_t* symtab;
66         stab_t* best_symtab = 0;
67         uint32_t best_func = 0;
68         
69         // ugly and unsorted
70         for (symtab = stab; symtab < estab; symtab++) {
71                 // only consider functions, type = 36
72                 if ((symtab->n_type == 36) && 
73                     (symtab->n_value <= address) && 
74                         (symtab->n_value > best_func)) {
75                         best_func = symtab->n_value;
76                         best_symtab = symtab;
77                 }
78         }
79         // maybe the first stab really is the right one...  we'll see.
80         if (best_symtab == 0)
81                 return "Function not found!";
82         return stabstr + best_symtab->n_strx;
83 }
84
85 int
86 mon_backtrace(int argc, char **argv, struct Trapframe *tf)
87 {
88         uint32_t* ebp, eip;
89         int i = 1;
90         ebp = (uint32_t*)read_ebp();    
91         // this is the retaddr for what called backtrace
92         eip = *(ebp + 1);
93         // jump back a frame (out of mon_backtrace)
94         ebp = (uint32_t*)(*ebp);
95         cprintf("Stack Backtrace:\n");
96         // on each iteration, ebp holds the stack frame and eip is a retaddr in that func
97         while (ebp != 0) {
98                 cprintf("%02d EBP: %x EIP: %x Function: %s\n   Args: %08x %08x %08x %08x %08x\n",
99                                 i++,
100                         ebp,
101                                 eip,
102                                 function_of(eip),
103                                 *(ebp + 2),
104                                 *(ebp + 3),
105                                 *(ebp + 4),
106                                 *(ebp + 5),
107                                 *(ebp + 6)
108                                 );
109                 eip = *(ebp + 1);
110                 ebp = (uint32_t*)(*ebp);
111         }
112
113         return 0;
114 }
115
116 int
117 mon_reboot(int argc, char **argv, struct Trapframe *tf)
118 {
119         cprintf("[Irish Accent]: She's goin' down, Cap'n!\n");
120         outb(0x92, 0x3);
121         cprintf("Should have rebooted.  Doesn't work yet in KVM...\n");
122         return 0;
123 }
124
125
126
127 /***** Kernel monitor command interpreter *****/
128
129 #define WHITESPACE "\t\r\n "
130 #define MAXARGS 16
131
132 static int
133 runcmd(char *buf, struct Trapframe *tf)
134 {
135         int argc;
136         char *argv[MAXARGS];
137         int i;
138
139         // Parse the command buffer into whitespace-separated arguments
140         argc = 0;
141         argv[argc] = 0;
142         while (1) {
143                 // gobble whitespace
144                 while (*buf && strchr(WHITESPACE, *buf))
145                         *buf++ = 0;
146                 if (*buf == 0)
147                         break;
148
149                 // save and scan past next arg
150                 if (argc == MAXARGS-1) {
151                         cprintf("Too many arguments (max %d)\n", MAXARGS);
152                         return 0;
153                 }
154                 argv[argc++] = buf;
155                 while (*buf && !strchr(WHITESPACE, *buf))
156                         buf++;
157         }
158         argv[argc] = 0;
159
160         // Lookup and invoke the command
161         if (argc == 0)
162                 return 0;
163         for (i = 0; i < NCOMMANDS; i++) {
164                 if (strcmp(argv[0], commands[i].name) == 0)
165                         return commands[i].func(argc, argv, tf);
166         }
167         cprintf("Unknown command '%s'\n", argv[0]);
168         return 0;
169 }
170
171 void
172 monitor(struct Trapframe *tf)
173 {
174         char *buf;
175
176         cprintf("Welcome to the JOS kernel monitor!\n");
177         cprintf("Type 'help' for a list of commands.\n");
178
179
180         while (1) {
181                 buf = readline("K> ");
182                 if (buf != NULL)
183                         if (runcmd(buf, tf) < 0)
184                                 break;
185         }
186 }
187
188 /*
189 // return EIP of caller.
190 // does not work if inlined.
191 // putting at the end of the file seems to prevent inlining.
192 unsigned
193 read_eip()
194 {
195         uint32_t callerpc;
196         __asm __volatile("movl 4(%%ebp), %0" : "=r" (callerpc));
197         return callerpc;
198 }
199
200 char* function_at(uint32_t address) 
201 {
202         extern stab_t stab[], estab[];
203         extern char stabstr[];
204         stab_t* symtab;
205         
206         for (symtab = stab; symtab < estab; symtab++) {
207                 if (symtab->n_value == address)
208                         return stabstr + symtab->n_strx;
209         }
210         return "Function not found!";
211 }
212
213 uint32_t called_address(uint32_t retaddr)
214 {
215         // retaddr - 4 is the offset to the previous call, which
216         // gets added to the next inst after call when calling
217         return (uint32_t)(retaddr + *(uint32_t*)(retaddr - 4));
218         //used like this:
219         //function_at(called_address(*(ebp + 1))),
220 }
221 */