Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
cscope:
Program
cscope is an interactive program that locates specified elements of code
in C, lex, or yacc source files. With cscope, you can search and edit your
source files more efficiently than you could with a typical editor. That's
because cscope supports function calls--when a function is being called,
when it is doing the calling--as well as C language identifiers and
keywords.
When cscope has completed this search, it prints a list. Each list entry
contains the name of the file, the number of the line, and the text of
the line in which cscope has found the specified code. In our case, the
list also includes the names of the functions that call the specified
function. You now have the option of requesting another search or
examining one of the listed lines with the editor. If you choose the
latter, cscope invokes the editor for the file in which the line appears,
with the cursor on that line. You can now view the code in context and,
if you wish, edit the file as any other file. You can then return to the
menu from the editor to request a new search.
Because the procedure you follow depends on the task at hand, there
is no single set of instructions for using cscope. For an extended
example of its use, review the cscope session described in the next
1
section. It shows how you can locate a bug in a program without
learning all the code.
Basic Use
Suppose you are given responsibility for maintaining the program prog.
You are told that an error message, out of storage, sometimes appears
just as the program starts up. Now you want to use cscope to locate
the parts of the code that are generating the message. Here is how
you do it.
In a C shell, type:
In a C shell, type:
2
You may have to write an interface between cscope and your editor. For
details, see Command-Line Syntax for Editors.
If you want to use cscope only for browsing (without editing), you can
set the VIEWER environment variable to pg and export VIEWER. cscope will
then invoke pg instead of vi.
% cscope
To browse through selected source files, invoke cscope with the names
of those files as arguments:
cscope builds the symbol cross-reference table the first time it is used
on the source files for the program to be browsed. By default, the
table is stored in the file cscope.out in the current directory. On a
subsequent invocation, cscope rebuilds the cross-reference only if a
source file has been modified or the list of source files is different.
When the cross-reference is rebuilt, the data for the unchanged files is
copied from the old cross-reference, which makes rebuilding faster
than the initial build, and reduces startup time for subsequent
invocations.
3
Now let's return to the task we undertook at the beginning of this
section: to identify the problem that is causing the error message out
of storage to be printed. You have invoked cscope, the cross-reference
table has been built. The cscope menu of tasks appears on the screen.
% cscope
cscope Press the ? key for help
Find this C symbol:
Find this global definition:
Find functions called by this function:
Find functions calling this function:
Find this text string:
Change this text string:
Find this egrep pattern:
Find this file:
Find files #including this file:
Press the Return key to move the cursor down the screen (with
wraparound at the bottom of the display), and ^p (Control-p) to move
the cursor up; or use the up (ua) and down (da) arrow keys. You can
manipulate the menu and perform other tasks with the following
single-key commands:
^c
Toggle ignore/use letter case when searching. For example, a search for FILE
matches file and File when ignoring the letter case.
^r Rebuild cross-reference.
! Start an interactive shell. Type ^d to return to cscope.
4
^l Redraw the screen.
? Display the list of commands.
^d Exit cscope.
If the first character of the text for which you are searching matches
one of these commands, you can escape the command by entering a \
(backslash) before the character.
Now move the cursor to the fifth menu item, Find this text string,
enter the text out of storage, and press the Return key.
$ cscope
cscope Press the ? key for help
Find this C symbol
Find this global definition
Find functions called by this function
Find functions calling this function
Find this text string: out of storage
Change this text string
Find this egrep pattern
Find this file
Find files #including this file
Note – Follow the same procedure to perform any other task listed in
the menu except the sixth, Change this text string. Because this task is
slightly more complex than the others, there is a different procedure
for performing it. For a description of how to change a text string, see
Examples.
cscopesearches for the specified text, finds one line that contains it,
and reports its finding.
5
Find functions called by this function:
Find functions calling this function:
Find this text string:
Change this text string:
Find this egrep pattern:
Find this file:
Find files #including this file:
After cscope shows you the results of a successful search, you have
several options. You may want to change one of the lines or examine
the code surrounding it in the editor. Or, if cscope has found so many
lines that a list of them does not fit on the screen at once, you may
want to look at the next part of the list. The following table shows the
commands available after cscope has found the specified text:
Edit the file referenced by this line. The number you type corresponds to an item
1 -9
in the list of lines printed by cscope.
Again, if the first character of the text for which you are searching
matches one of these commands, you can escape the command by
entering a backslash before the character.
Now examine the code around the newly found line. Enter 1 (the
number of the line in the list). The editor is invoked with the file
alloc.c with the cursor at the beginning of line 63 of alloc.c.
6
{
return(alloctest(realloc(p, (unsigned) size)));
}
/* check for memory allocation failure */
static char *
alloctest(p)
char *p;
{
if (p == NULL) {
(void) fprintf(stderr, "\n%s: out of storage\n", argv0);
exit(1);
}
return(p);
}
~
~
~
~
~
~
~
"alloc.c" 67 lines, 1283 characters
You can see that the error message is generated when the variable p is
NULL. To determine how an argument passed to alloctest() could have
been NULL, you must first identify the functions that call alloctest().
Exit the editor by using normal quit conventions. You are returned to
the menu of tasks. Now type alloctest after the fourth item, Find
functions calling this function.
7
cscope finds and lists three such functions.
Now you want to know which functions call mymalloc(). cscope finds ten
such functions. It lists nine of them on the screen and instructs you to
press the space bar to see the rest of the list.
8
8 19 h = (struct cmd *) mymalloc(sizeof(struct
addcmd
history.c cmd));
Because you know that the error message out of storage is generated
at the beginning of the program, you can guess that the problem may
have occurred in the function dispinit() (display initialization).
void
dispinit()
{
/* calculate the maximum displayed reference lines */
lastdispline = FLDLINE - 4;
mdisprefs = lastdispline - REFLINE + 1;
if (mdisprefs > 9) {
mdisprefs = 9;
}
/* allocate the displayed line array */
displine = (int *) mymalloc(mdisprefs * sizeof(int));
}
^L/* display a page of the references */
void
display()
{
char file[PATHLEN + 1]; /* file name */
char function[PATLEN + 1];/* function name */
char linenum[NUMLEN + 1]; /* line number */
int screenline; /* screen line number */
int width; /* source line display width */
register int i, j;
"display.c" 622 lines, 14326 characters
9
mymalloc() failed because it was called either with a very large number
or a negative number. By examining the possible values of FLDLINE and
REFLINE, you can see that there are situations in which the value of
mdisprefs is negative, that is, in which you are trying to call mymalloc()
with a negative number.
void
dispinit()
{
/* calculate the maximum displayed reference lines */
lastdispline = FLDLINE - 4;
mdisprefs = lastdispline - REFLINE + 1;
if (mdisprefs > 9) {
mdisprefs = 9;
}
/* allocate the displayed line array */
displine = (int *) mymalloc(mdisprefs * sizeof(int));
}
^L/* display a page of the references */
void
display()
{
char file[PATHLEN + 1]; /* file name */
char function[PATLEN + 1];/* function name */
char linenum[NUMLEN + 1]; /* line number */
int screenline; /* screen line number */
int width; /* source line display width */
register int i, j;
"display.c" 622 lines, 14326 characters
10
You have fixed the problem we began investigating at the beginning of
this section. Now if prog is run in a window with too few lines, it does
not simply fail with the unedifying error message out of storage.
Instead, it checks the window size and generates a more meaningful
error message before exiting.
Command-Line Options
% cscope
is equivalent to:
% cscope *.[chly]
We have also seen that you can browse through selected source files
by invoking cscope with the names of those files as arguments:
% cscope -s dir1,dir2,dir3
cscope builds a cross-reference for all the source files in the specified
directories as well as the current directory. To browse through all of
the source files whose names are listed in file (file names separated by
spaces, tabs, or new-lines), invoke cscope with the -i option and the
name of the file containing the list:
% cscope -i file
If your source files are in a directory tree, use the following commands
to browse through all of them:
11
% find . -name '*.[chly]' -print | sort > file
% cscope -i file
The -I option can be used for cscope in the same way as the -I option
to cc. See Include Files.
You can specify a cross-reference file other than the default cscope.out
by invoking the -f option. This is useful for keeping separate symbol
cross-reference files in the same directory. You may want to do this if
two programs are in the same directory, but do not share all the same
files:
In this example, the source files for two programs, admin and delta, are
in the same directory, but the programs consist of different groups of
files. By specifying different symbol cross-reference files when you
invoke cscope for each set of source files, the cross-reference
information for the two programs is kept separate.
You can use the -pn option to specify that cscope display the path
name, or part of the path name, of a file when it lists the results of a
search. The number you give to -p stands for the last n elements of
the path name you want to be displayed. The default is 1, the name of
the file itself. So if your current directory is home/common, the command:
% cscope -p2
12
% echo 'cscope -b' | batch
Once the cross-reference is built, and as long as you have not changed
a source file or the list of source files in the meantime, you need only
specify:
% cscope
The -d option instructs cscope not to update the symbol cross-reference. You can use it
to save time if you are sure that no such changes have been made; cscope does not check
the source files for changes.
Note – Use the -d option with care. If you specify -d under the
erroneous impression that your source files have not been changed,
cscope refers to an outdated symbol cross-reference in responding to
your queries.
View Paths
Suppose you use cscope to browse through the three files that
comprise prog1, namely, f1.c, f2.c, and f3.c. You would set VPATH to
/usr/you and /fs1/ofc and export it, as in:
13
In a Bourne shell, type:
In a C shell, type:
% cscope
The program locates all the files in the view path. In case duplicates
are found, cscope uses the file whose parent directory appears earlier
in VPATH. Thus, if f2.c is in your directory, and all three files are in the
official directory, cscope examines f2.c from your directory, and f1.c
and f3.c from the official directory.
The first directory in VPATH must be a prefix of the directory you will be
working in, usually $HOME. Each colon-separated directory in VPATH must
be absolute: it should begin at /.
cscope and editor calls can be stacked. That is, when cscope puts you in
the editor to view a reference to a symbol and there is another
reference of interest, you can invoke cscope again from within the
editor to view the second reference without exiting the current
invocation of either cscope or the editor. You can then back up by
exiting the most recent invocation with the appropriate cscope and
editor commands.
Examples
14
the new text, displays the lines containing the old text, and waits for
you to specify which of these lines you want it to change.
cscope displays the lines containing the specified text string, and waits
for you to select those in which you want the text to be changed.
15
You know that the constant 100 in lines 1, 2, and 3 of the list (lines 4,
26, and 8 of the listed source files) should be changed to MAXSIZE. You
also know that 0100 in read.c and 100.0 in err.c (lines 4 and 5 of the
list) should not be changed. You select the lines you want changed
with the following single-key commands:
In this case, enter 1, 2, and 3. The numbers you type are not printed
on the screen. Instead, cscope marks each list item you want to be
changed by printing a > (greater than) symbol after its line number in
the list.
16
Select lines to change (press the ? key for help):
Now type ^d to change the selected lines. cscope displays the lines that
have been changed and prompts you to continue.
Changed lines:
char s[MAXSIZE];
for (i = 0; i < MAXSIZE; i++)
if (c < MAXSIZE) {
Press the RETURN key to continue:
When you press Return in response to this prompt, cscope redraws the
screen, restoring it to its state before you selected the lines to be
changed.
The next step is to add the #define for the new symbol MAXSIZE.
Because the header file in which the #define is to appear is not among
the files whose lines are displayed, you must escape to the shell by
typing !. The shell prompt appears at the bottom of the screen. Then
enter the editor and add the #define.
17
To resume the cscope session, quit the editor and type ^d to exit the
shell.
First, edit the function by using the second menu item, Find this global
definition. Next, find out where the function is called. Use the fourth
menu item, Find functions calling this function, to obtain a list of all
the functions that call it. With this list, you can either invoke the editor
for each line found by entering the list number of the line individually,
or invoke the editor for all the lines automatically by typing ^e. Using
cscope to make this kind of change ensures that none of the functions
you need to edit are overlooked.
At times, you may want to see how a proposed change affects your
code.
cscope invokes the vi editor by default. You can override the default
setting by assigning your preferred editor to the EDITOR environment
variable and exporting EDITOR, as described in Step 1: Set Up the
Environment. However, cscope expects the editor it uses to have a
command-line syntax of the form:
as does vi. If the editor you want to use does not have this command-
line syntax, you must write an interface between cscope and the editor.
18
Suppose you want to use ed. Because ed does not allow specification of
a line number on the command-line, you cannot use it to view or edit
files with cscope unless you write a shell script that contains the
following line:
/usr/bin/ed $2
Let's name the shell script myedit. Now set the value of EDITOR to your
shell script and export EDITOR:
In a C shell, type:
When cscope invokes the editor for the list item you have specified,
say, line 17 in main.c, it invokes your shell script with the command-
line:
myedit then discards the line number ($1) and calls ed correctly with the
file name ($2). Of course, you are not moved automatically to line 17
of the file and must execute the appropriate ed commands to display
and edit the line.
19
Sorry, I need to know a more specific terminal type than "unknown"
set and export the TERM variable as described in Step 1: Set Up the
Environment.
In this tutorial you'll learn how to set up Cscope with a large project. We'll use as our
example the Linux kernel source code, but the basic steps are the same for any other large
project, including C++ or Java projects.
1. Get the source. First get the source code. You can download the Linux kernel
source from http://www.kernel.org. For the rest of this tutorial, I'll assume you've
downloaded Linux 2.4.18 and installed it into /home/jru/linux-2.4.18.
Note: Make sure you've got enough disk space: the kernel tarball alone is 30 MB,
it expands into 150 MB of source code, and the Cscope database we'll generate
will gobble up another 20-100+ MB (depending on how much of the kernel code
you decide to include in the database). You can put the Cscope database on a
different disk partition than the source code if you need to.
2. Figure out where you want to put your Cscope database files. I'll assume
you'll use /home/jru/cscope as the directory to store your database and
associated files.
3. Generate cscope.files with a list of files to be scanned. For some projects,
you may want to include every C source file in the project's directories in your
Cscope database. In that case you can skip this step, and just use 'cscope -R' in
the project's top-level directory to build your Cscope database. But if there's some
code that you wish to exclude, and/or your project contains C++ or Java source
code (by default Cscope only parses files with the .c, .h, .y, or .l extensions),
you'll need to generate a file called cscope.files, which should contain the
name of all files that you wish to have Cscope scan (one file name per line).
You'll probably want to use absolute paths (at least if you're planning to use the
Cscope database within an editor), so that you can use the database from
directories other than the one you create. The commands I show will first cd to
root, so that find prints out absolute paths.
20
For many projects, your find command may be as as simple as
cd /
find /my/project/dir -name '*.java'
>/my/cscope/dir/cscope.files
For the Linux kernel, it's a little trickier, since we want to exclude all the code in
the docs and scripts directories, plus all of the architecture and assembly code for
all chips except for the beloved Intel x86 (which I'm guessing is the architecture
you're interested in). Additionally, I'm excluding all kernel driver code in this
example (they more than double the amount of code to be parsed, which bloats
the Cscope database, and they contain many duplicate definitions, which often
makes searching harder. If you are interested in the driver code, omit the relevant
line below, or modify it to print out only the driver files you're interested in):
LNX=/home/jru/linux-2.4.18
cd /
find $LNX
\
-path "$LNX/arch/*" ! -path "$LNX/arch/i386*" -prune -o
\
-path "$LNX/include/asm-*" ! -path "$LNX/include/asm-i386*"
-prune -o \
-path "$LNX/tmp*" -prune -o
\
-path "$LNX/Documentation*" -prune -o
\
-path "$LNX/scripts*" -prune -o
\
-path "$LNX/drivers*" -prune -o
\
-name "*.[chxsS]" -print >/home/jru/cscope/cscope.files
While find commands can be a little tricky to write, for large projects they are
much easier than editing a list of files manually, and you can also cut and paste a
solution from someone else.
4. Generate the Cscope database. Now it's time to generate the Cscope database:
5. cd /home/jru/cscope # the directory with 'cscope.files'
6. cscope -b -q -k
The -b flag tells Cscope to just build the database, and not launch the Cscope
GUI. The -q causes an additional, 'inverted index' file to be created, which makes
searches run much faster for large databases. Finally, -k sets Cscope's 'kernel'
mode--it will not look in /usr/include for any header files that are #included in
your source files (this is mainly useful when you are using Cscope with operating
system and/or C library source code, as we are here).
21
On my 900 MHz Pentium III system (with a standard IDE disk), parsing this
subset of the Linux source takes only 12 seconds, and results in 3 files
(cscope.out, cscope.in.out, and cscope.po.out) that take up a total of 25
megabytes.
7. Using the database. If you like to use vim or emacs/xemacs, I recommend that
you learn how to run Cscope within one of these editors, which will allow you to
run searches easily within your editor. We have a tutorial for Vim, and emacs
users will of course be clever enough to figure everything out from the helpful
comments in the cscope/contrib/xcscope/ directory of the Cscope
distribution.
Otherwise, you can use the standalone Cscope curses-based GUI, which lets you
run searches, then launch your favorite editor (i.e., whatever $EDITOR is set to in
your environment, or 'vi' by default) to open on the exact line of the search result.
If you use the standalone Cscope browser, make sure to invoke it via
cscope -d
This tells Cscope not to regenerate the database. Otherwise you'll have to wait
while Cscope checks for modified files, which can take a while for large projects,
even when no files have changed. If you accidentally run 'cscope', without any
flags, you will also cause the database to be recreated from scratch without the
fast index or kernel modes being used, so you'll probably need to rerun your
original cscope command above to correctly recreate the database.
If there are new files in your project, rerun your 'find' command to update
cscope.files if you're using it.
Then simply invoke cscope the same way (and in the same directory) as you did
to generate the database initially (i.e., cscope -b -q -k).
22
List lines containing this text string
out of storage
Press the <Return> key. The cscope tool searches for the specified text and finds one line
that contains it.
NOTE: The same procedure is followed to perform any other task listed in the menu,
except the sixth, changing a text string. For a description and examples of changing a text
string, see ``Changing a text string''.
File Line
argv[0] );
23
List functions calling this function:
After cscope shows the results of a successful search in this way, you have several
options. For example, you may want to edit one of the lines found. If cscope has found
several lines and a list of them will not fit on the screen at once, you may want to look at
the next part of the list. The following table shows the commands available after cscope
has found the specified text.
Command Meaning
1-9 edit this line
(the number you type corresponds to an item
in the list of lines printed by cscope)
space display the lines after the current line
+ display the lines after the current line
- display the lines before the current line
<Ctrl>e edit all lines
> append the list of lines being displayed to a file
NOTE: If the first character of the text you are searching for matches one of these
commands, precede it with a ``\'' (backslash).
Now examine the code around the newly found line. Enter ``1'' (the number of the line in
the list). The editor will be invoked with the file alloc.c; the cursor will be at the
beginning of line 56 of the text file.
{
return(alloctest(realloc(p,(unsigned) size)));
}
/* check for memory allocation failure */
static char *
alloctest(p)
char *p;
24
if (p == NULL) {
(void) fprintf(stderr,
argv[0]);
exit(C);
return(p);
By examining the code, you learn that the error message is generated when the variable p
is NULL. To determine how an argument passed to alloctest could have been NULL, you
must first identify the functions that call alloctest.
Exit the editor by using normal write and quit conventions, and return to the menu of
tasks. Now request a list of functions that call alloctest, as shown in the next example:
File Line
argv[0] );
25
cscope finds and lists three such functions:
Functions calling this function: alloctest
(unsigned) size)));
size)));
Now you need to know which functions call mymalloc. cscope finds ten such functions.
It lists seven of them on the screen and instructs you to press the space bar to see the rest
of the list.
Functions calling this function: mymalloc
+ 1), s));
mymalloc(nsrcdirs*sizeof(char*));
+ n);
26
mymalloc(msrcfiles*sizeof(char*));
mymalloc(msrcfiles*sizeof(char*));
mymalloc(sizeof(char *));
mymalloc(mdisprefs * sizeof(int));
Because you know that the error message ("out of storage") is generated at the
beginning of the program, you can guess that the problem may have occurred in the
function dispinit (display initialization). To view dispinit, the seventh function on the
list, type ``7'':
void dispinit()
{
/* calculate the maximum displayed reference lines */
lastdispline = FLDLINE - 4;
mdisprefs = lastdispline - REFLINE + 1;
if (mdisprefs > 9) {
mdisprefs = 9;
}
/* allocate the displayed line array */
displine = (int *) mymalloc(mdisprefs * sizeof(int));
}
^L/* display a page of the references */
void display(){
27
char file[PATHLEN + 1]; /* file name */
register int i, j;
Examining this code, you will see that mymalloc failed because it was called with a
negative number. You are now in a position to fix the problem. The program needs a
mechanism such that if the value of the variable mdisprefs is negative, it will abort after
printing a meaningful error message.
28