1 /* List lines of source files for GDB, the GNU debugger.
2 Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
4 GDB is distributed in the hope that it will be useful, but WITHOUT ANY
5 WARRANTY. No author or distributor accepts responsibility to anyone
6 for the consequences of using it or for whether it serves any
7 particular purpose or works at all, unless he says so in writing.
8 Refer to the GDB General Public License for full details.
10 Everyone is granted permission to copy, modify and redistribute GDB,
11 but only under the conditions described in the GDB General Public
12 License. A copy of this license is supposed to have been given to you
13 along with GDB so you can know your rights and responsibilities. It
14 should be in a file named COPYING. Among other things, the copyright
15 notice and this notice must be preserved on all copies.
17 In other words, go ahead and share GDB, but don't try to stop
18 anyone else from sharing it farther. Help stamp out software hoarding!
22 #include <sys/param.h>
26 #include "initialize.h"
29 /* Path of directories to search for source files.
30 Same format as the PATH environment variable's value. */
32 static char *source_path
;
34 /* Symtab of default file for listing lines of. */
36 struct symtab
*current_source_symtab
;
38 /* Default next line to list. */
40 int current_source_line
;
42 /* Line number of last line printed. Default for various commands.
43 current_source_line is usually, but not always, the same as this. */
45 static int last_line_listed
;
47 /* First line number listed by last listing command. */
49 static int first_line_listed
;
53 /* Set the source file default for the "list" command,
54 specifying a symtab. */
57 select_source_symtab (s
)
58 register struct symtab
*s
;
62 struct symtabs_and_lines sals
;
63 struct symtab_and_line sal
;
65 /* Make the default place to list be the function `main'
67 if (lookup_symbol ("main", 0, VAR_NAMESPACE
))
69 sals
= decode_line_spec ("main", 1);
72 current_source_symtab
= sal
.symtab
;
73 current_source_line
= sal
.line
- 9;
77 /* If there is no `main', use the last symtab in the list,
78 which is actually the first found in the file's symbol table.
79 But ignore .h files. */
82 char *name
= s
->filename
;
83 int len
= strlen (name
);
84 if (! (len
> 2 && !strcmp (&name
[len
- 2], ".h")))
85 current_source_symtab
= s
;
89 current_source_line
= 1;
96 printf ("Source directories searched: %s\n", source_path
);
102 register struct symtab
*s
;
104 if (getwd (wd
) == NULL
)
105 perror_with_name ("getwd");
107 source_path
= savestring (wd
, strlen (wd
));
109 /* Forget what we learned about line positions in source files;
110 must check again now since files may be found in
111 a different directory now. */
112 for (s
= symtab_list
; s
; s
= s
->next
)
113 if (s
->line_charpos
!= 0)
115 free (s
->line_charpos
);
121 directory_command (dirname
, from_tty
)
125 char *old
= source_path
;
128 if (getwd (wd
) == NULL
)
129 perror_with_name ("getwd");
133 if (query ("Reinitialize source path to %s? ", wd
))
142 register int len
= strlen (dirname
);
144 extern char *index ();
146 if (index (dirname
, ':'))
147 error ("Please add one directory at a time to the source path.");
148 if (dirname
[len
- 1] == '/')
149 /* Sigh. "foo/" => "foo" */
150 dirname
[--len
] == '\0';
152 while (dirname
[len
- 1] == '.')
156 /* "." => getwd () */
160 else if (dirname
[len
- 2] == '/')
165 dirname
[--len
] = '\0';
170 /* "...foo/." => "...foo" */
171 dirname
[len
-= 2] = '\0';
178 if (dirname
[0] != '/')
179 dirname
= concat (wd
, "/", dirname
);
181 dirname
= savestring (dirname
, len
);
182 make_cleanup (free
, dirname
);
184 if (stat (dirname
, &st
) < 0)
185 perror_with_name (dirname
);
186 if ((st
.st_mode
& S_IFMT
) != S_IFDIR
)
187 error ("%s is not a directory.", dirname
);
190 len
= strlen (dirname
);
194 if (!strncmp (tem
, dirname
, len
)
195 && (tem
[len
] == '\0' || tem
[len
] == ':'))
197 printf ("\"%s\" is already in the source path.\n",
201 tem
= index (tem
, ':');
206 source_path
= concat (old
, ":", dirname
);
216 /* Open a file named STRING, searching path PATH (dir names sep by colons)
217 using mode MODE and protection bits PROT in the calls to open.
218 If TRY_CWD_FIRST, try to open ./STRING before searching PATH.
219 (ie pretend the first element of PATH is ".")
220 If FILENAMED_OPENED is non-null, set it to a newly allocated string naming
221 the actual file opened (this string will always start with a "/"
223 If a file is found, return the descriptor.
224 Otherwise, return -1, with errno set for the last name we tried to open. */
226 /* >>>> This should only allow files of certain types,
227 >>>> eg executable, non-directory */
229 openp (path
, try_cwd_first
, string
, mode
, prot
, filename_opened
)
235 char **filename_opened
;
238 register char *filename
;
239 register char *p
, *p1
;
243 while (string
[0] == '.' && string
[1] == '/')
246 if (try_cwd_first
|| string
[0] == '/')
249 fd
= open (filename
, mode
, prot
);
250 if (fd
>= 0 || string
[0] == '/')
254 filename
= (char *) alloca (strlen (path
) + strlen (string
) + 2);
256 for (p
= path
; p
; p
= p1
? p1
+ 1 : 0)
258 p1
= (char *) index (p
, ':');
264 strncpy (filename
, p
, len
);
266 strcat (filename
, "/");
267 strcat (filename
, string
);
269 fd
= open (filename
, mode
, prot
);
276 *filename_opened
= (char *) 0;
277 else if (filename
[0] == '/')
278 *filename_opened
= savestring (filename
, strlen (filename
));
281 *filename_opened
= concat (current_directory
, "/", filename
);
287 /* Create and initialize the table S->line_charpos that records
288 the positions of the lines in the source file, which is assumed
289 to be open on descriptor DESC.
290 All set S->nlines to the number of such lines. */
293 find_source_lines (s
, desc
)
298 register char *data
, *p
, *end
;
300 int lines_allocated
= 1000;
301 int *line_charpos
= (int *) xmalloc (lines_allocated
* sizeof (int));
302 extern int exec_mtime
;
305 if (get_exec_file () != 0 && exec_mtime
< st
.st_mtime
)
306 printf ("Source file is more recent than executable.\n");
308 data
= (char *) alloca (st
.st_size
);
309 myread (desc
, data
, st
.st_size
);
310 end
= data
+ st
.st_size
;
318 if (nlines
== lines_allocated
)
319 line_charpos
= (int *) xrealloc (line_charpos
,
320 sizeof (int) * (lines_allocated
*= 2));
321 line_charpos
[nlines
++] = p
- data
;
325 s
->line_charpos
= (int *) xrealloc (line_charpos
, nlines
* sizeof (int));
328 /* Return the character position of a line LINE in symtab S.
329 Return 0 if anything is invalid. */
332 source_line_charpos (s
, line
)
337 if (!s
->line_charpos
|| line
<= 0) return 0;
338 if (line
> s
->nlines
)
340 return s
->line_charpos
[line
- 1];
343 /* Return the line number of character position POS in symtab S. */
346 source_charpos_line (s
, chr
)
347 register struct symtab
*s
;
350 register int line
= 0;
353 if (s
== 0 || s
->line_charpos
== 0) return 0;
354 lnp
= s
->line_charpos
;
355 /* Files are usually short, so sequential search is Ok */
356 while (line
< s
->nlines
&& *lnp
<= chr
)
361 if (line
>= s
->nlines
)
366 /* Get full pathname and line number positions for a symtab.
367 Return nonzero if line numbers may have changed.
368 Set *FULLNAME to actual name of the file as found by `openp',
369 or to 0 if the file is not found. */
372 get_filename_and_charpos (s
, line
, fullname
)
377 register int desc
, linenums_changed
= 0;
379 desc
= openp (source_path
, 0, s
->filename
, O_RDONLY
, 0, &s
->fullname
);
387 *fullname
= s
->fullname
;
388 if (s
->line_charpos
== 0) linenums_changed
= 1;
389 if (linenums_changed
) find_source_lines (s
, desc
);
391 return linenums_changed
;
394 /* Print text describing the full name of the source file S
395 and the line number LINE and its corresponding character position.
396 The text starts with two Ctrl-z so that the Emacs-GDB interface
399 Return 1 if successful, 0 if could not find the file. */
402 identify_source_line (s
, line
)
406 if (s
->line_charpos
== 0)
407 get_filename_and_charpos (s
, line
, 0);
408 if (s
->fullname
== 0)
410 printf ("\032\032%s:%d:%d\n", s
->fullname
, line
, s
->line_charpos
[line
- 1]);
414 /* Print source lines from the file of symtab S,
415 starting with line number LINE and stopping before line number STOPLINE. */
418 print_source_lines (s
, line
, stopline
)
424 register FILE *stream
;
425 int nlines
= stopline
- line
;
427 desc
= openp (source_path
, 0, s
->filename
, O_RDONLY
, 0, &s
->fullname
);
429 perror_with_name (s
->filename
);
431 if (s
->line_charpos
== 0)
432 find_source_lines (s
, desc
);
434 if (line
< 1 || line
>= s
->nlines
)
437 error ("Line number out of range; %s has %d lines.",
438 s
->filename
, s
->nlines
);
441 if (lseek (desc
, s
->line_charpos
[line
- 1], 0) < 0)
444 perror_with_name (s
->filename
);
447 current_source_symtab
= s
;
448 current_source_line
= line
;
449 first_line_listed
= line
;
451 stream
= fdopen (desc
, "r");
458 last_line_listed
= current_source_line
;
459 printf ("%d\t", current_source_line
++);
462 if (c
< 040 && c
!= '\t' && c
!= '\n')
465 fputc (c
+ 0100, stdout
);
471 } while (c
!= '\n' && (c
= fgetc (stream
)) >= 0);
478 list_command (arg
, from_tty
)
482 struct symtabs_and_lines sals
, sals_end
;
483 struct symtab_and_line sal
, sal_end
;
492 if (symtab_list
== 0)
493 error ("Listing source lines requires symbols.");
495 /* "l" or "l +" lists next ten lines. */
497 if (arg
== 0 || !strcmp (arg
, "+"))
499 if (current_source_symtab
== 0)
500 error ("No default source file yet. Do \"help list\".");
501 print_source_lines (current_source_symtab
, current_source_line
,
502 current_source_line
+ 10);
506 /* "l -" lists previous ten lines, the ones before the ten just listed. */
507 if (!strcmp (arg
, "-"))
509 if (current_source_symtab
== 0)
510 error ("No default source file yet. Do \"help list\".");
511 print_source_lines (current_source_symtab
,
512 max (first_line_listed
- 10, 1),
517 /* Now if there is only one argument, decode it in SAL
519 If there are two arguments, decode them in SAL and SAL_END
520 and clear NO_END; however, if one of the arguments is blank,
521 set DUMMY_BEG or DUMMY_END to record that fact. */
528 sals
= decode_line_1 (&arg1
, 0, 0, 0);
530 if (! sals
.nelts
) return; /* C++ */
533 error ("Unreasonable listing request");
540 /* Record whether the BEG arg is all digits. */
542 for (p
= arg
; p
!= arg1
&& *p
>= '0' && *p
<= '9'; p
++);
543 linenum_beg
= (p
== arg1
);
545 while (*arg1
== ' ' || *arg1
== '\t')
551 while (*arg1
== ' ' || *arg1
== '\t')
558 sals_end
= decode_line_1 (&arg1
, 0, 0, 0);
560 sals_end
= decode_line_1 (&arg1
, 0, sal
.symtab
, sal
.line
);
561 if (! sals_end
.nelts
) return; /* C++ */
562 sal_end
= sals_end
.sals
[0];
563 free (sals_end
.sals
);
568 error ("Junk at end of line specification.");
570 if (!no_end
&& !dummy_beg
&& !dummy_end
571 && sal
.symtab
!= sal_end
.symtab
)
572 error ("Specified start and end are in different files.");
573 if (dummy_beg
&& dummy_end
)
574 error ("Two empty args do not say what lines to list.");
576 /* if line was specified by address,
577 first print exactly which line, and which file.
578 In this case, sal.symtab == 0 means address is outside
579 of all known source files, not that user failed to give a filename. */
583 error ("No source file for address 0x%x.", sal
.pc
);
584 sym
= find_pc_function (sal
.pc
);
586 printf ("0x%x is in %s (%s, line %d).\n",
587 sal
.pc
, SYMBOL_NAME (sym
), sal
.symtab
->filename
, sal
.line
);
589 printf ("0x%x is in %s, line %d.\n",
590 sal
.pc
, sal
.symtab
->filename
, sal
.line
);
593 /* If line was not specified by just a line number,
594 and it does not imply a symtab, it must be an undebuggable symbol
595 which means no source code. */
597 if (! linenum_beg
&& sal
.symtab
== 0)
598 error ("No line number known for %s.", arg
);
600 /* If this command is repeated with RET,
601 turn it into the no-arg variant. */
606 if (dummy_beg
&& sal_end
.symtab
== 0)
607 error ("No default source file yet. Do \"help list\".");
609 print_source_lines (sal_end
.symtab
, max (sal_end
.line
- 9, 1),
611 else if (sal
.symtab
== 0)
612 error ("No default source file yet. Do \"help list\".");
614 print_source_lines (sal
.symtab
, max (sal
.line
- 5, 1), sal
.line
+ 5);
616 print_source_lines (sal
.symtab
, sal
.line
,
617 dummy_end
? sal
.line
+ 10 : sal_end
.line
+ 1);
620 /* Print info on range of pc's in a specified line. */
623 line_info (arg
, from_tty
)
627 struct symtabs_and_lines sals
;
628 struct symtab_and_line sal
;
629 int start_pc
, end_pc
;
633 sal
.symtab
= current_source_symtab
;
634 sal
.line
= last_line_listed
;
638 sals
= decode_line_spec (arg
);
643 error ("unreasonable line info request");
647 /* If this command is repeated with RET,
648 turn it into the no-arg variant. */
655 error ("No source file specified.");
657 && find_line_pc_range (sal
.symtab
, sal
.line
, &start_pc
, &end_pc
))
659 if (start_pc
== end_pc
)
660 printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n",
661 sal
.line
, sal
.symtab
->filename
, start_pc
);
663 printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n",
664 sal
.line
, sal
.symtab
->filename
, start_pc
, end_pc
);
665 /* x/i should display this line's code. */
666 set_next_address (start_pc
);
667 /* Repeating "info line" should do the following line. */
668 last_line_listed
= sal
.line
+ 1;
671 printf ("Line number %d is out of range for \"%s\".\n",
672 sal
.line
, sal
.symtab
->filename
);
675 /* Commands to search the source file for a regexp. */
678 forward_search_command (regex
, from_tty
)
683 register FILE *stream
;
684 int line
= last_line_listed
+ 1;
687 msg
= (char *) re_comp (regex
);
691 if (current_source_symtab
== 0)
692 error ("No default source file yet. Do \"help list\".");
694 /* Search from last_line_listed+1 in current_source_symtab */
696 desc
= openp (source_path
, 0, current_source_symtab
->filename
,
697 O_RDONLY
, 0, ¤t_source_symtab
->fullname
);
699 perror_with_name (current_source_symtab
->filename
);
701 if (current_source_symtab
->line_charpos
== 0)
702 find_source_lines (current_source_symtab
, desc
);
704 if (line
< 1 || line
>= current_source_symtab
->nlines
)
707 error ("Expression not found");
710 if (lseek (desc
, current_source_symtab
->line_charpos
[line
- 1], 0) < 0)
713 perror_with_name (current_source_symtab
->filename
);
716 stream
= fdopen (desc
, "r");
719 char buf
[4096]; /* Should be reasonable??? */
720 register char *p
= buf
;
727 } while (c
!= '\n' && (c
= fgetc (stream
)) >= 0);
729 /* we now have a source line in buf, null terminate and match */
731 if (re_exec (buf
) > 0)
735 print_source_lines (current_source_symtab
,
737 current_source_line
= max (line
- 5, 1);
743 printf ("Expression not found\n");
748 reverse_search_command (regex
, from_tty
)
753 register FILE *stream
;
754 int line
= last_line_listed
- 1;
757 msg
= (char *) re_comp (regex
);
761 if (current_source_symtab
== 0)
762 error ("No default source file yet. Do \"help list\".");
764 /* Search from last_line_listed-1 in current_source_symtab */
766 desc
= openp (source_path
, 0, current_source_symtab
->filename
,
767 O_RDONLY
, 0, ¤t_source_symtab
->fullname
);
769 perror_with_name (current_source_symtab
->filename
);
771 if (current_source_symtab
->line_charpos
== 0)
772 find_source_lines (current_source_symtab
, desc
);
774 if (line
< 1 || line
>= current_source_symtab
->nlines
)
777 error ("Expression not found");
780 if (lseek (desc
, current_source_symtab
->line_charpos
[line
- 1], 0) < 0)
783 perror_with_name (current_source_symtab
->filename
);
786 stream
= fdopen (desc
, "r");
790 char buf
[4096]; /* Should be reasonable??? */
791 register char *p
= buf
;
798 } while (c
!= '\n' && (c
= fgetc (stream
)) >= 0);
800 /* We now have a source line in buf; null terminate and match. */
802 if (re_exec (buf
) > 0)
806 print_source_lines (current_source_symtab
,
808 current_source_line
= max (line
- 5, 1);
812 if (fseek (stream
, current_source_symtab
->line_charpos
[line
- 1], 0) < 0)
815 perror_with_name (current_source_symtab
->filename
);
819 printf ("Expression not found\n");
827 current_source_symtab
= 0;
830 add_com ("directory", class_files
, directory_command
,
831 "Add directory DIR to end of search path for source files.\n\
832 With no argument, reset the search path to just the working directory\n\
833 and forget cached info on line positions in source files.");
835 add_info ("directories", directories_info
,
836 "Current search path for finding source files.");
838 add_info ("line", line_info
,
839 "Core addresses of the code for a source line.\n\
840 Line can be specified as\n\
841 LINENUM, to list around that line in current file,\n\
842 FILE:LINENUM, to list around that line in that file,\n\
843 FUNCTION, to list around beginning of that function,\n\
844 FILE:FUNCTION, to distinguish among like-named static functions.\n\
845 Default is to describe the last source line that was listed.\n\n\
846 This sets the default address for \"x\" to the line's first instruction\n\
847 so that \"x/i\" suffices to start examining the machine code.\n\
848 The address is also stored as the value of \"$_\".");
850 add_com ("forward-search", class_files
, forward_search_command
,
851 "Search for regular expression (see regex(3)) from last line listed.");
852 add_com_alias ("search", "forward-search", class_files
, 0);
854 add_com ("reverse-search", class_files
, reverse_search_command
,
855 "Search backward for regular expression (see regex(3)) from last line listed.");
857 add_com ("list", class_files
, list_command
,
858 "List specified function or line.\n\
859 With no argument, lists ten more lines after or around previous listing.\n\
860 \"list -\" lists the ten lines before a previous ten-line listing.\n\
861 One argument specifies a line, and ten lines are listed around that line.\n\
862 Two arguments with comma between specify starting and ending lines to list.\n\
863 Lines can be specified in these ways:\n\
864 LINENUM, to list around that line in current file,\n\
865 FILE:LINENUM, to list around that line in that file,\n\
866 FUNCTION, to list around beginning of that function,\n\
867 FILE:FUNCTION, to distinguish among like-named static functions.\n\
868 *ADDRESS, to list around the line containing that address.\n\
869 With two args if one is empty it stands for ten lines away from the other arg.");