Browsing the source code

The simplest way is to use the good old grep. For instance to find all instances of the symbol runprogram, you would do this:

cd ~/os161/src/kern
grep -r runprogram
More sophisticated way include using cscope and cflow.

Browsing the source code with cscope

Install the tools

First, make sure you have the tools installed. If you are working on the department server, the tools will most likely already be there. Otherwise, ask your course staff for help. If you are using the virtual appliance, execute these commands (they will work on any Ubuntu machine):
sudo apt-get install emacs23 cscope cscope-el
If you are on a MacOS, see instructions for emacs installation below, and install cscope via brew:
  brew install cscope

Now generate the cscope database on your kernel:

cd ~/os161/src/kern
find . -name "*.c" -o -name "*.S" -o -name "*.h" > cscope.files
cscope -q -R -b -i cscope.files

The second command will generate a list of source files and the third command will build a cscope database.

Now you can search for symbols using the cscope browser:

cscope -d
Or you can use cscope within your favourite editor, such as vim or emacs.

Using cscope with vim

  1. In your home directory, create a new folder:
    mkdir -p ~/.vim/plugin
    
  2. Move to that directory and download the cscope mappings file which will be used by Vim:
    cd ~/.vim/plugin
    wget http://cscope.sourceforge.net/cscope_maps.vim
    

    We assume that you have already created the cscope database in the previous step, which is needed to browse the files.

  3. Learn how to use the mappings.

    You can check the cscope_maps.vim for details about the mappings that can be used. There are three useful mappings which you might find helpful:

    • CTRL + ']'

      If you move the cursor to any function call (or struct, ...) and issue this mapping, it will take you to the definition of the function call. For example:

      1. Open kern/main/main.c with Vim:
        vim kern/main/main.c
        
      2. Go the kmain() function and move the cursor to any place on the boot() function call. Issue the mapping by pressing CTRL and ] at the same time. You will see that now you're at the definition of the boot() function call. There might be multiple places where a function is defined. In that case Vim will give you a list and you can choose the one that you think is relevant to what you're searching for.
    • CTRL + 't'

      This will take you back up in the stack to the point before you issued CTRL + ]. You can issue this mapping from anywhere ( the cursor doesn't have to be on anything). If you issue this mapping after you jumped to the boot() definition, you will be taken back to the kmain() function.

    • CTRL + '\' and then 's'

      You perform this mapping in a similar way to the CTRL+ ], however this mapping will give you a list of all the places where the given function ( or struct or anything else) is used throughout the source code.

  4. Support cscope while running Vim from any directory (Thanks to Augustine)

    For now, you can only use cscope with Vim if you run Vim from the same directory where the cscope tags are generated. To use cscope regardless from where you run Vim, you can add the following line to the ~/.vimrc file (assuming that you have generated the cscope files in ~/os161/src/):

    cs add $HOME/os161/src/cscope.out $HOME/os161/src/
    

    Make sure you generate the tags at the highest convenient level. Source.

  5. Advanced cscope options. Use cs help command inside Vim to explore more advanced options:
     
    :cs help
    cscope commands:
    add  : Add a new database             (Usage: add file|dir [pre-path] [flags])
    find : Query for a pattern            (Usage: find c|d|e|f|g|i|s|t name)
           c: Find functions calling this function
           d: Find functions called by this function
           e: Find this egrep pattern
           f: Find this file
           g: Find this definition
           i: Find files #including this file
           s: Find this C symbol
           t: Find this text string
    help : Show this message              (Usage: help)
    kill : Kill a connection              (Usage: kill #)
    reset: Reinit all connections         (Usage: reset)
    show : Show connections               (Usage: show)
    

    For example, to lookup where is strcmp method is defined, try:

      :cs find g strcmp
    

    You should see something similar to this:

    Cscope tag: strcmp
       #   line  filename / context / line
       1     48  src/common/libc/string/strcmp.c <>
                 strcmp(const char *a, const char *b)
       2      1  src/kern/compile/DUMBVM/.depend.strcmp.c <>
                 strcmp.o: ../../../common/libc/string/strcmp.c ../../include/types.h \
       3      1  src/kern/compile/SYNCHPROBS/.depend.strcmp.c <>
                 strcmp.o: ../../../common/libc/string/strcmp.c ../../include/types.h \
       4    144  /usr/include/string.h <>
                 extern int strcmp (const char *__s1, const char *__s2)
    Type number and  (empty cancels): 
    

    where you can enter 1 to jump to the method implementation.

Using xcscope with emacs

Configure xcscope and emacs on Linux or MacOS

  1. Install emacs for Linux or MacOS by searching Google. This should be pretty straightforward. For MacOS, you'll need to be able to start emacs from the command line. To be able to do that, create the following script. Let's assume you save it in the file named memacs.
    #!/bin/sh
    /Applications/Emacs.app/Contents/MacOS/Emacs "$@"
    

    Make it executable and put it somewhere in your home directory, where makes sense:

    chmod u+x ./memacs
    mkdir $home/bin
    mv memacs $home/bin
    

    Now add $home/bin to your path by editing your .shrc or .cshrc file, and you'll be able to launch emacs from command line by typing memacs.

  2. Download the latest version of xcscope.el, for example here. There are other implementations too, if you prefer. We assume that you put the downloaded file at the root of your home directory, but if you choose to put it elsewhere, you'd need to modify the load-path in the next set of instructions.
  3. Add the following lines to your $home/.emacs file:
      (add-to-list 'load-path "~/")
      (require 'xcscope)
    
    Now if you want to map cscope commands to certain quick-access keys on your keyboard, add the following lines to your .emacs file, adjusting them as you see fit:
      (define-key global-map [(f3)]  'cscope-set-initial-directory)
      (define-key global-map [(f4)]  'cscope-find-global-definition)
      (define-key global-map [(f5)]  'cscope-find-this-symbol)
      (define-key global-map [(f6)]  'cscope-find-called-functions)
      (define-key global-map [(f7)]  'cscope-find-functions-calling-this-function)
      (define-key global-map [(f8)]  'cscope-find-this-file)
      (define-key global-map [(f9)]  'cscope-find-egrep-pattern)
    

Use cscope within emacs

Now if your start emacs from the same directory as the location of your cscope database (e.g., ~/os161/src/kern), you can use the commands we added to your ~/.emacs file to search for symbol definitions and browse the code.

For instance, pressing f5 (assuming the mapping we set up above) and then typing the symbol name (e.g., runprogram) you ask cscope to tell you where this symbol is defined and used. As you begin using the cscope commands, cscope will bring up the source file containing the symbol in the top emacs window and the cscope command buffer in the bottom window. You can position the cursor on the symbol of interest, in the source-file window, and press f5, which will make cscope show this symbol in the command buffer, and then press Enter in the command buffer. You can also split the emacs window vertically prior to using cscope (by pressing Ctrl-x 3 -- this way the code buffer and the command buffer will be side-by-side, giving you more vertical space. Take a look at the commands above, added to the ~/.emacs file to explore what else you can do with cscope.

Generating a callgraph with cflow

The simplest way to run cflow is to navigate to the directory of interest and launch the command on the source files contained therein. For example:

cd ~/os161/src/kern/main
cflow --include=s *.c

This command tells cflow to generate a direct call graph and to include all static symbols.

For more information on controlling cflow output, visualizing the graphs it generates and integrating it with makefiles, read here.