This file may be updated, so check back periodically
% cd $HOME/cs350-os161/os161-1.99/kern/conf % ./config ASST2 % cd ../compile/ASST2 % bmake depend % bmake % bmake install
You encountered the DEBUG mechanism in A0, but as a reminder:
DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", (unsigned long) filesize, (unsigned long) vaddr);The DEBUG macro and the various flags (like DB_EXEC) are defined in kern/include/lib.h.
u_int32_t dbflags = 0;will turn off all debugging output, while
u_int32_t dbflags = DB_EXEC|DB_THREADS;will turn off everything except DEBUG statements that are labeled with DB_EXEC or DB_THREADS.
You can control the number of processors in the simulated machine by changing the SYS/161 configuration file, sys161.conf. Look for a line like this:
31 mainboard ramsize=524288 cpus=1The cpus=1 indicates that that simulated machine has a single CPU (processor). To simulate more CPUs, just use change the CPU count. For example, changing the line above to
31 mainboard ramsize=524288 cpus=4will give you a system with 4 CPUs.
So that you're not constantly editing the configuration file, you can create multiple different configuration files and pass the one you want to the simulator when it starts, using the -c option, e.g,
sys161 -c my-config-file.conf kernel
Here is something to think about when you do start worrying about those exit status codes: a process's exit status code may be needed long after that process has exited. Where will you keep the code, and when will it be safe to forget it?
#include ‹types.h›will always come first. For more details and rules about #include, see the comments at the top of kern/include/types.h. Symptoms of failure to observe the these rules include complaints about errors in header files during kernel compilation.
#ifndef _LIB_H_ #define _LIB_H_as well as a corresponding
#endif /* _LIB_H_ */at the end of the file. This ensures that lib.h will never be included more than once during a compilation. Every other kernel include file includes similar code, for the same reason. If you add a new header file to your kernel, you should follow a similar convention to ensure that your header will never be included twice. Failure to do so can lead to compilation errors, such as complaints about multiply-defined symbols or variables.
You build all of the OS/161 application programs when you run bmake in the directory cs350-os161/os161-1.99. When you do this, the application program executable files are copied into subdirectories under cs350-os161/root/.
Once your OS/161 kernel has booted, you can launch an application program using the p command from the kernel menu. For example, to run the palin program, which is located in testbin, use the following command
OS/161 kernel [? for menu]: p testbin/palinAs usual, you can pass commands to the kernel on sys161 command line, e.g.,
sys161 kernel "p testbin/palin"
# Old/default value # 31 busctl ramsize=524288 # Changed to 4 MB. 31 busctl ramsize=4194304In particular, you will probably have to do this for applications like forktest.
Note that the YouTube channel for CS 350 contains a video tutorial on how to use gdb. In addition there is some information included below.
If you type < ctrl-g > in the sys161 window, the OS pauses and waits for a debugger to attach. This is useful if you don't have a debugger already attached and you want to see what's happening.
If you create a file called .gdbinit and put it in $HOME/cs350-os161/root directory (assuming that is where you are running cs350-gdb from) gdb will load commands from that file when it starts up. Here's an example of a simple, useful .gdbinit file:
dir ../os161-1.11/kern/compile/ASST0 target remote unix:.sockets/gdb break panicThis way, you don't have to type the target command to connect to sys161 every time you run the debugger, and you don't have to type the dir command to tell gdb where to find your build files. This .gdbinit also sets a breakpoeint at the kernel's panic function, so that gdb will grab control in case the kernel panics. Note that you will want to change dir ../os161-1.11/kern/compile/ASST0 for subsequent assignments, e.g, for assignment one, your .gdbinit file should contain dir ../os161-1.11/kern/compile/ASST1 instead.
This is an example gdb session to show what output to expect and how to up up the stack trace to look at a simple variable. This session was produced by Tim Brecht using a previous (older) version of OS/161 (so your code may not look the same). His comments are on the lines that start with "//". Each comment refers to the output that follows it.
// Start cs350-gdb. % cs350-gdb kernel GNU gdb 6.0 Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "--host=i686-pc-linux-gnu --target=mips-elf"... __start () at ../../arch/mips/mips/start.S:24 24 addiu sp, sp, -20 Current language: auto; currently asm Breakpoint 1 at 0x80010948: file ../../lib/kprintf.c, line 111. // Continue execution. This stops and waits for input into os161. // In the window running sys161 -w kernel after I type something like // p testbin/program it runs and eventually panics. (gdb) continue Continuing. Breakpoint 1, panic (fmt=0x8002fe6c "Assertion failed: %s, at %s:%d (%s)\n") at ../../lib/kprintf.c:111 111 if (evil==0) { Current language: auto; currently c // I want to find out who called panic and why. // Where shows the stack trace of who called what and all // the parameters. // panic is where we are currently. // It was called from lock_destroy at line 181 of thread/synch.c // It was called from proc_entry_init at line 601 of userprog/syscalls.c // etc. // proc_entry_init was the function that called lock_destroy. (gdb) where #0 panic (fmt=0x8002fe6c "Assertion failed: %s, at %s:%d (%s)\n") at ../../lib/kprintf.c:111 #1 0xffffffff8001740c in lock_destroy (lock=0x800c3e20) at ../../thread/synch.c:181 #2 0xffffffff80022b30 in proc_entry_init (pid=2) at ../../userprog/syscalls.c:601 #3 0xffffffff800258dc in sys_waitpid (pid=2, status=0x7fffff90, options=0, retval=0x800fcf18) at ../../userprog/syscalls.c:1367 #4 0xffffffff8000c6b8 in mips_syscall (tf=0x800fcf6c) at ../../arch/mips/mips/syscall.c:145 #5 0xffffffff8000cb68 in mips_trap (tf=0x800fcf6c) at ../../arch/mips/mips/trap.c:134 // Move up the stack. (gdb) up #1 0xffffffff8001740c in lock_destroy (lock=0x800c3e20) at ../../thread/synch.c:181 181 assert(lock->held == 0); // Move up the stack. (gdb) up #2 0xffffffff80022b30 in proc_entry_init (pid=2) at ../../userprog/syscalls.c:601 601 lock_destroy(p->ft_lock); // Move up the stack. (gdb) up #3 0xffffffff800258dc in sys_waitpid (pid=2, status=0x7fffff90, options=0, retval=0x800fcf18) at ../../userprog/syscalls.c:1367 1367 proc_entry_init(pid); // Print out some info about the current thread. (gdb) print *curthread $1 = {t_pcb = {pcb_switchstack = 2148519408, pcb_kstack = 2148519936, pcb_ininterrupt = 0, pcb_badfaultfunc = 0, pcb_copyjmp = {2148517880, 2147537544, 0, 0, 0, 0, 0, 0, 0, 0, 2148517880}}, t_name = 0x800d2d00 "ourtests/conc-io", t_sleepaddr = 0x0, t_stack = 0x800fc000 "o?=\021o?=3", t_vmspace = 0x800f7360, t_cwd = 0x800d2f40, pid = 1} // Print out the value of pid as it is inside of userprog/syscalls.c in the // function sys_waitpid at the time of the call to proc_entry_init. (gdb) print pid $2 = 2 // Print out the value of pid in hex. (gdb) print/x pid $2 = 0x2 // x/i Examine (x) specified memory location as an instruction (i). // Print out the instruction located at address 0xffffffff8000c6b8. // Note that I got this address from the above stack trace. // It shows you that this is address is 520 bytes inside of mips_syscall. // This can be really helpful if OS/161 dies and sys161 just prints // out the epc (which contains the address of the instruction // that generated the execption. (gdb) x/i 0xffffffff8000c6b8 0x8000c6b8: j 0x8000c6f0 // x/i Examine (x) specified memory location as an instruction (i). // Print out the instruction located at address 0xffffffff8001740c. // Note that I got this address from the above stack trace. // It shows you that this address is 148 bytes inside of lock_destroy. (gdb) x/i 0xffffffff8001740c 0x8001740c : lw v0,32(s8) The list command is useful for finding the line of source that contains the faulting instruction (note the *): Something else that can be done (from a different version of the code) (gdb) list *0x800197c4 0x800197c4 is in kmain (../../main/main.c:164). 159 kmain(char *arguments) 160 { 161 char *bad_ptr = NULL; 162 boot(); 163 164 *bad_ptr = 0; 165 166 menu(arguments); 167 168 /* Should not get here *