CS644 hw1 Linux Syscalls and Warmup on Xinu due Sunday midnight, Feb. 14, 20 points. Useful gdb commands, beyond the basics, for low-level access. For basic commands, see the gdb link from www.cs.umb.edu/ulab. disas main disassembly i reg register display x/x 0x12345 hex display of location, like md x/s 0x12345 string display x/10i $pc display 10 instructions starting from current pc si single-step by one instruction b *0x12345 set breakpoint at address 0. Post a test message in thread "hw1 test" in the cs644 Google group, that is, reply to the posting of that name. 1. UNIX (Linux) Syscalls See the class handout of a script of a run on Solaris that found the "ta" instruction that is the system call instruction for the Sparc processor. Now we want to find the "int" instruction used for system calls with the x86 processor (for all OS's running on x86.) Similarly run gdb on a.out produced on our linux system sf06.cs.umb.edu by compiling the following hi.c with -g for debugging: hi.c: main() { write(1,"hi\n",3); write(1,"hi2\n",4); return 6; /* should result in syscall exit(6) */ } Here we are requesting output to stdout (fd=1) via the write system call. Produce a script of gdb showing: a. Setting a breakpoint in main and running the program to it. b. The assembly language in main (disas main). How are the 3 args of write being communicated to write here? Show the string "hi\n" by finding the string address in the assembly code of main and using "x/s 0x...". (Note that on Sun Sparc the function arguments are passed in registers but in x86 they are passed on the stack, because the x86 processor has so few general registers.) c. After execution has reached main, set a breakpoint at the *second call* to write, and proceed to it. Then single-step with si until you see that you're in a "write" routine within the C library (i.e. above 0x40000000). Use disas
to display the code and see the system call. The reason to use a second write call here is that the first call to write requires a lengthy lookup taking about 500 instructions, (resolving the DLL function location) whereas the subsequent calls are fast and thus easy to trace. You can prove to yourself that the system call you found is used the first time too by breakpointing it once you have its address. d. Use si to proceed across the system call. Note how the whole system call execution appears at user level to be due to this one instruction. Is it int $0x80 or sysenter or what? At what (virtual) address is the syscall instruction? Does gdb display a name for this area of code? e. Set a breakpoint on the return instruction at the end of main and proceed to it. Then si back into the startup module (this is one way to find it.) Edit in labels for the parts a, b, etc., and the 3 args to write. Leave this as linux_syscalls.script in your hw1 dir. 2. Run "strace a.out" for the Linux program from 1. above. Do "man strace" on Linux to find out about this tool. Solaris has a similar tool called truss. See the C library being located and mmap'd in. The last few lines of the strace output describe the execution of main. Leave this in strace.script. 3. Use ps to find out the pid of your shell process. Then use "cat /proc//maps" as shown on Love, pg. 260 to see the memory areas of that user program. Determine the range of addresses for its code, data, heap (malloc'd data), C library DLL, any other DLLs, and the user stack, in file pmap.txt. 4. Write a little user program for Linux, memtest.c, that accepts a number on the command line, and does a single malloc of that number of MB of memory, and then uses memset to set all that memory to 0. After these operations, do a sleep(30) to make the program sleep for 30 seconds, giving you time to get its pmap. Run the program when noone else is running it, and see how large a contiguous memory area you can get. (It is safe to run it when others are, but you might get a different answer.) Also get the pmap information for the largest case and explain it, in memtest.txt. You might want to try strace on this program too. NOTE: as of Tuesday, Feb. 9, the SAPCs are still not reliably available because of a network problem. I'll post to the Google group when they are working properly. 5. Warmup on Xinu, and using remote gdb See $pcex/gdb.script for getting started with remote gdb. Before starting the script, build and download prodcons.lnx, starting from $xuex/prodcons.c and $xuex/Makefile. Do the "gdb" command in Tutor to turn debugging over to remote gdb. Then open another window and run i386-gdb. Recall that prodcons has a top-level user process and two other processes, prod and cons. In addition, Xinu has a "null process", process 0--read Comer, p. 61. This program does no user input, so it is easy to work with under remote gdb. Make a script (in xinu.script) of running remote gdb to show how you did this: a. Run i386-gdb on ulab, and use "tar rem /dev/remgdb11" or whatever sys # you are using. (Systems 11-14 have faster download.) b. Set breakpoints at create and main. c. Do "c" to start the program (or "set $eip = 0x100100" followed by "c" to restart) d. It should hit your create breakpoint as it creates the top-level user process. The special null process is specially set up, not by the create syscall, so you won't see a breakpoint hit for that. Continue from there. e. It should hit your main breakpoint as it starts the user process. Continue. It should hit create again, as process "cons" is created. Continue. f. It should hit create again, as process "prod" is created. Use "finish" to let it do the create call and deliver you back to the caller in main. g. Now the system has 4 processes, prnull and 3 user processes. The one just created shows you the return value from create: 47. Why 47? There are 50 process slots in this version of Xinu, up from 10 in the original. See p. 54 and correct NPROC from 10 to 50. See $xuker/../h/proc.h for the current version. Good idea to print this out. The null process gets slot 0, while all the other processes are allocated from the bottom of the table, so 49 for main, 48 for the first worker and 47 for the second. Verify this by printing out proctab[0], the pentry for the null process, and proctab[49], proctab[48], and proctab[47]. You can see the pnames for each process. Note that gdb can print whole structs at once, or even arrays of structs. h. Looking more carefully at these pentries, print out their entry points in the code area (paddr), in hex: gdb) p/x proctab[0].paddr etc. Also print out pbase and plimit in hex for each. 6. Draw a picture of memory, showing the code areas and 4 stacks, in xinu.txt, or on paper. Files to deliver: 1. linux_syscalls.script 2. strace.script 3. pmap.txt 4. memtest.c, memtest.txt 5. xinu.script 6. xinu.txt (or paper)