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